From 5cead172cd2a6ff56d314dac4320f20fe91102f6 Mon Sep 17 00:00:00 2001 From: wanjunlei <53003665+wanjunlei@users.noreply.github.com> Date: Tue, 5 Jul 2022 16:04:33 +0800 Subject: [PATCH] update notification manager to v2.0 (#5030) Signed-off-by: wanjunlei --- Makefile | 2 +- cmd/controller-manager/app/server.go | 3 + go.mod | 13 +- go.sum | 5 +- pkg/apiserver/apiserver.go | 14 +- pkg/client/clientset/versioned/clientset.go | 28 + .../versioned/fake/clientset_generated.go | 14 + .../clientset/versioned/fake/register.go | 4 + .../clientset/versioned/scheme/register.go | 4 + .../typed/notification/v2beta2/config.go | 184 +++++ .../typed/notification/v2beta2/doc.go | 20 + .../typed/notification/v2beta2/fake/doc.go | 20 + .../notification/v2beta2/fake/fake_config.go | 133 ++++ .../v2beta2/fake/fake_notification_client.go | 52 ++ .../v2beta2/fake/fake_receiver.go | 133 ++++ .../notification/v2beta2/fake/fake_router.go | 133 ++++ .../notification/v2beta2/fake/fake_silence.go | 133 ++++ .../v2beta2/generated_expansion.go | 27 + .../v2beta2/notification_client.go | 104 +++ .../typed/notification/v2beta2/receiver.go | 184 +++++ .../typed/notification/v2beta2/router.go | 184 +++++ .../typed/notification/v2beta2/silence.go | 184 +++++ .../versioned/typed/types/v1beta2/doc.go | 20 + .../versioned/typed/types/v1beta2/fake/doc.go | 20 + .../types/v1beta2/fake/fake_types_client.go | 35 + .../types/v1beta2/generated_expansion.go | 19 + .../typed/types/v1beta2/types_client.go | 84 +++ .../informers/externalversions/generic.go | 11 + .../notification/interface.go | 8 + .../notification/v2beta2/config.go | 89 +++ .../notification/v2beta2/interface.go | 66 ++ .../notification/v2beta2/receiver.go | 89 +++ .../notification/v2beta2/router.go | 89 +++ .../notification/v2beta2/silence.go | 89 +++ .../listers/notification/v2beta2/config.go | 68 ++ .../v2beta2/expansion_generated.go | 35 + .../listers/notification/v2beta2/receiver.go | 68 ++ .../listers/notification/v2beta2/router.go | 68 ++ .../listers/notification/v2beta2/silence.go | 68 ++ .../notification/notification_controller.go | 170 ++++- .../notification_controller_test.go | 103 ++- pkg/kapis/notification/v2beta1/handler.go | 26 +- pkg/kapis/notification/v2beta1/register.go | 10 + pkg/kapis/notification/v2beta2/handler.go | 217 +++--- pkg/kapis/notification/v2beta2/register.go | 128 +++- pkg/models/notification/notification.go | 344 +++++++-- pkg/models/notification/notification_test.go | 2 +- .../v1alpha3/notification/notification.go | 58 +- .../notification/notification_test.go | 35 +- .../resources/v1alpha3/resource/resource.go | 8 +- staging/src/kubesphere.io/api/go.mod | 1 + staging/src/kubesphere.io/api/go.sum | 2 + .../api/notification/v2beta1/config_types.go | 5 +- .../notification/v2beta1/receiver_types.go | 2 + .../notification/v2beta2/config_conversion.go | 340 +++++++++ .../api/notification/v2beta2/config_types.go | 21 +- .../v2beta2/notificationmanager_types.go | 90 ++- .../v2beta2/receiver_conversion.go | 330 +++++++++ .../notification/v2beta2/receiver_types.go | 72 +- .../api/notification/v2beta2/register.go | 8 +- .../api/notification/v2beta2/router_types.go | 70 ++ .../api/notification/v2beta2/silence_types.go | 111 +++ .../api/notification/v2beta2/types.go | 8 + .../v2beta2/zz_generated.deepcopy.go | 536 ++++++++++++++ .../federatednotificationconfig_types.go | 2 + .../federatednotificationreceiver_types.go | 2 + .../federatednotificationconfig_types.go | 184 +++++ .../federatednotificationreceiver_types.go | 117 +++ .../federatednotificationrouter_types.go | 64 ++ .../federatednotificationsilence_types.go | 64 ++ .../api/types/v1beta2/register.go | 57 ++ .../kubesphere.io/api/types/v1beta2/types.go | 108 +++ .../types/v1beta2/zz_generated.deepcopy.go | 681 ++++++++++++++++++ vendor/github.com/robfig/cron/v3/.gitignore | 22 + vendor/github.com/robfig/cron/v3/.travis.yml | 1 + vendor/github.com/robfig/cron/v3/LICENSE | 21 + vendor/github.com/robfig/cron/v3/README.md | 125 ++++ vendor/github.com/robfig/cron/v3/chain.go | 92 +++ .../robfig/cron/v3/constantdelay.go | 27 + vendor/github.com/robfig/cron/v3/cron.go | 355 +++++++++ vendor/github.com/robfig/cron/v3/doc.go | 231 ++++++ vendor/github.com/robfig/cron/v3/go.mod | 3 + vendor/github.com/robfig/cron/v3/logger.go | 86 +++ vendor/github.com/robfig/cron/v3/option.go | 45 ++ vendor/github.com/robfig/cron/v3/parser.go | 434 +++++++++++ vendor/github.com/robfig/cron/v3/spec.go | 188 +++++ vendor/modules.txt | 20 +- 87 files changed, 7877 insertions(+), 253 deletions(-) create mode 100644 pkg/client/clientset/versioned/typed/notification/v2beta2/config.go create mode 100644 pkg/client/clientset/versioned/typed/notification/v2beta2/doc.go create mode 100644 pkg/client/clientset/versioned/typed/notification/v2beta2/fake/doc.go create mode 100644 pkg/client/clientset/versioned/typed/notification/v2beta2/fake/fake_config.go create mode 100644 pkg/client/clientset/versioned/typed/notification/v2beta2/fake/fake_notification_client.go create mode 100644 pkg/client/clientset/versioned/typed/notification/v2beta2/fake/fake_receiver.go create mode 100644 pkg/client/clientset/versioned/typed/notification/v2beta2/fake/fake_router.go create mode 100644 pkg/client/clientset/versioned/typed/notification/v2beta2/fake/fake_silence.go create mode 100644 pkg/client/clientset/versioned/typed/notification/v2beta2/generated_expansion.go create mode 100644 pkg/client/clientset/versioned/typed/notification/v2beta2/notification_client.go create mode 100644 pkg/client/clientset/versioned/typed/notification/v2beta2/receiver.go create mode 100644 pkg/client/clientset/versioned/typed/notification/v2beta2/router.go create mode 100644 pkg/client/clientset/versioned/typed/notification/v2beta2/silence.go create mode 100644 pkg/client/clientset/versioned/typed/types/v1beta2/doc.go create mode 100644 pkg/client/clientset/versioned/typed/types/v1beta2/fake/doc.go create mode 100644 pkg/client/clientset/versioned/typed/types/v1beta2/fake/fake_types_client.go create mode 100644 pkg/client/clientset/versioned/typed/types/v1beta2/generated_expansion.go create mode 100644 pkg/client/clientset/versioned/typed/types/v1beta2/types_client.go create mode 100644 pkg/client/informers/externalversions/notification/v2beta2/config.go create mode 100644 pkg/client/informers/externalversions/notification/v2beta2/interface.go create mode 100644 pkg/client/informers/externalversions/notification/v2beta2/receiver.go create mode 100644 pkg/client/informers/externalversions/notification/v2beta2/router.go create mode 100644 pkg/client/informers/externalversions/notification/v2beta2/silence.go create mode 100644 pkg/client/listers/notification/v2beta2/config.go create mode 100644 pkg/client/listers/notification/v2beta2/expansion_generated.go create mode 100644 pkg/client/listers/notification/v2beta2/receiver.go create mode 100644 pkg/client/listers/notification/v2beta2/router.go create mode 100644 pkg/client/listers/notification/v2beta2/silence.go create mode 100644 staging/src/kubesphere.io/api/notification/v2beta2/config_conversion.go create mode 100644 staging/src/kubesphere.io/api/notification/v2beta2/receiver_conversion.go create mode 100644 staging/src/kubesphere.io/api/notification/v2beta2/router_types.go create mode 100644 staging/src/kubesphere.io/api/notification/v2beta2/silence_types.go create mode 100644 staging/src/kubesphere.io/api/types/v1beta2/federatednotificationconfig_types.go create mode 100644 staging/src/kubesphere.io/api/types/v1beta2/federatednotificationreceiver_types.go create mode 100644 staging/src/kubesphere.io/api/types/v1beta2/federatednotificationrouter_types.go create mode 100644 staging/src/kubesphere.io/api/types/v1beta2/federatednotificationsilence_types.go create mode 100644 staging/src/kubesphere.io/api/types/v1beta2/register.go create mode 100644 staging/src/kubesphere.io/api/types/v1beta2/types.go create mode 100644 staging/src/kubesphere.io/api/types/v1beta2/zz_generated.deepcopy.go create mode 100644 vendor/github.com/robfig/cron/v3/.gitignore create mode 100644 vendor/github.com/robfig/cron/v3/.travis.yml create mode 100644 vendor/github.com/robfig/cron/v3/LICENSE create mode 100644 vendor/github.com/robfig/cron/v3/README.md create mode 100644 vendor/github.com/robfig/cron/v3/chain.go create mode 100644 vendor/github.com/robfig/cron/v3/constantdelay.go create mode 100644 vendor/github.com/robfig/cron/v3/cron.go create mode 100644 vendor/github.com/robfig/cron/v3/doc.go create mode 100644 vendor/github.com/robfig/cron/v3/go.mod create mode 100644 vendor/github.com/robfig/cron/v3/logger.go create mode 100644 vendor/github.com/robfig/cron/v3/option.go create mode 100644 vendor/github.com/robfig/cron/v3/parser.go create mode 100644 vendor/github.com/robfig/cron/v3/spec.go diff --git a/Makefile b/Makefile index 2885e4cbe..df59be823 100644 --- a/Makefile +++ b/Makefile @@ -6,7 +6,7 @@ # Produce CRDs that work back to Kubernetes 1.11 (no version conversion) CRD_OPTIONS ?= "crd:trivialVersions=true" -GV="network:v1alpha1 servicemesh:v1alpha2 tenant:v1alpha1 tenant:v1alpha2 devops:v1alpha1 iam:v1alpha2 devops:v1alpha3 cluster:v1alpha1 storage:v1alpha1 auditing:v1alpha1 types:v1beta1 quota:v1alpha2 application:v1alpha1 notification:v2beta1 gateway:v1alpha1" +GV="network:v1alpha1 servicemesh:v1alpha2 tenant:v1alpha1 tenant:v1alpha2 devops:v1alpha1 iam:v1alpha2 devops:v1alpha3 cluster:v1alpha1 storage:v1alpha1 auditing:v1alpha1 types:v1beta1 types:v1beta2 quota:v1alpha2 application:v1alpha1 notification:v2beta1 notification:v2beta2 gateway:v1alpha1" MANIFESTS="application/* cluster/* iam/* network/v1alpha1 quota/* storage/* tenant/* gateway/*" # App Version diff --git a/cmd/controller-manager/app/server.go b/cmd/controller-manager/app/server.go index b577a51ff..b7737ae06 100644 --- a/cmd/controller-manager/app/server.go +++ b/cmd/controller-manager/app/server.go @@ -32,6 +32,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/manager" "sigs.k8s.io/controller-runtime/pkg/manager/signals" "sigs.k8s.io/controller-runtime/pkg/webhook" + "sigs.k8s.io/controller-runtime/pkg/webhook/conversion" "kubesphere.io/kubesphere/cmd/controller-manager/app/options" "kubesphere.io/kubesphere/pkg/apis" @@ -244,6 +245,8 @@ func run(s *options.KubeSphereControllerManagerOptions, ctx context.Context) err } hookServer.Register("/validate-quota-kubesphere-io-v1alpha2", &webhook.Admission{Handler: resourceQuotaAdmission}) + hookServer.Register("/convert", &conversion.Webhook{}) + klog.V(2).Info("registering metrics to the webhook server") // Add an extra metric endpoint, so we can use the the same metric definition with ks-apiserver // /kapis/metrics is independent of controller-manager's built-in /metrics diff --git a/go.mod b/go.mod index 731089df5..bca0bd3a4 100644 --- a/go.mod +++ b/go.mod @@ -82,8 +82,6 @@ require ( github.com/prometheus/client_golang v1.11.0 github.com/prometheus/common v0.26.0 github.com/prometheus/prometheus v1.8.2-0.20200907175821-8219b442c864 - github.com/shirou/gopsutil v0.0.0-20180427012116-c95755e4bcd7 // indirect - github.com/shirou/w32 v0.0.0-20160930032740-bb4de0191aa4 // indirect github.com/sony/sonyflake v0.0.0-20181109022403-6d5bd6181009 github.com/speps/go-hashids v2.0.0+incompatible github.com/spf13/cobra v1.2.1 @@ -182,6 +180,7 @@ replace ( github.com/Shopify/logrus-bugsnag => github.com/Shopify/logrus-bugsnag v0.0.0-20171204204709-577dee27f20d github.com/Shopify/sarama => github.com/Shopify/sarama v1.19.0 github.com/Shopify/toxiproxy => github.com/Shopify/toxiproxy v2.1.4+incompatible + github.com/StackExchange/wmi => github.com/StackExchange/wmi v1.2.1 github.com/VividCortex/gohistogram => github.com/VividCortex/gohistogram v1.0.0 github.com/afex/hystrix-go => github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5 github.com/agnivade/levenshtein => github.com/agnivade/levenshtein v1.0.1 @@ -345,6 +344,7 @@ replace ( github.com/go-logfmt/logfmt => github.com/go-logfmt/logfmt v0.5.0 github.com/go-logr/logr => github.com/go-logr/logr v0.4.0 github.com/go-logr/zapr => github.com/go-logr/zapr v0.4.0 + github.com/go-ole/go-ole => github.com/go-ole/go-ole v1.2.6-0.20210915003542-8b1f7f90f6b1 github.com/go-openapi/analysis => github.com/go-openapi/analysis v0.19.10 github.com/go-openapi/errors => github.com/go-openapi/errors v0.19.4 github.com/go-openapi/jsonpointer => github.com/go-openapi/jsonpointer v0.19.3 @@ -407,6 +407,7 @@ replace ( github.com/google/go-github => github.com/google/go-github v17.0.0+incompatible github.com/google/go-querystring => github.com/google/go-querystring v1.0.0 github.com/google/gofuzz => github.com/google/gofuzz v1.1.0 + github.com/google/gops => github.com/google/gops v0.3.23 github.com/google/martian => github.com/google/martian v2.1.0+incompatible github.com/google/pprof => github.com/google/pprof v0.0.0-20200417002340-c6e0a841f49a github.com/google/renameio => github.com/google/renameio v0.1.0 @@ -490,6 +491,7 @@ replace ( github.com/karrick/godirwalk => github.com/karrick/godirwalk v1.10.3 github.com/kelseyhightower/envconfig => github.com/kelseyhightower/envconfig v1.4.0 github.com/kevinburke/ssh_config => github.com/kevinburke/ssh_config v0.0.0-20180830205328-81db2a75821e + github.com/keybase/go-ps => github.com/keybase/go-ps v0.0.0-20190827175125-91aafc93ba19 github.com/kisielk/errcheck => github.com/kisielk/errcheck v1.2.0 github.com/kisielk/gotool => github.com/kisielk/gotool v1.0.0 github.com/kisielk/sqlstruct => github.com/kisielk/sqlstruct v0.0.0-20150923205031-648daed35d49 @@ -638,6 +640,7 @@ replace ( github.com/rainycape/unidecode => github.com/rainycape/unidecode v0.0.0-20150907023854-cb7f23ec59be github.com/rcrowley/go-metrics => github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a github.com/retailnext/hllpp => github.com/retailnext/hllpp v1.0.1-0.20180308014038-101a6d2f8b52 + github.com/robfig/cron/v3 => github.com/robfig/cron/v3 v3.0.1 github.com/rogpeppe/fastuuid => github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af github.com/rogpeppe/go-charset => github.com/rogpeppe/go-charset v0.0.0-20180617210344-2471d30d28b4 github.com/rogpeppe/go-internal => github.com/rogpeppe/go-internal v1.3.0 @@ -654,6 +657,9 @@ replace ( github.com/segmentio/kafka-go => github.com/segmentio/kafka-go v0.2.0 github.com/sercand/kuberesolver => github.com/sercand/kuberesolver v2.4.0+incompatible github.com/sergi/go-diff => github.com/sergi/go-diff v1.0.0 + github.com/shirou/gopsutil => github.com/shirou/gopsutil v0.0.0-20180427012116-c95755e4bcd7 + github.com/shirou/gopsutil/v3 => github.com/shirou/gopsutil/v3 v3.21.9 + github.com/shirou/w32 => github.com/shirou/w32 v0.0.0-20160930032740-bb4de0191aa4 github.com/shopspring/decimal => github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24 github.com/shurcooL/httpfs => github.com/shurcooL/httpfs v0.0.0-20190707220628-8d4bc4ba7749 github.com/shurcooL/sanitized_anchor_name => github.com/shurcooL/sanitized_anchor_name v1.0.0 @@ -682,6 +688,8 @@ replace ( github.com/thanos-io/thanos => github.com/thanos-io/thanos v0.13.1-0.20200910143741-e0b7f7b32e9c github.com/tidwall/pretty => github.com/tidwall/pretty v1.0.0 github.com/tinylib/msgp => github.com/tinylib/msgp v1.1.0 + github.com/tklauser/go-sysconf => github.com/tklauser/go-sysconf v0.3.9 + github.com/tklauser/numcpus => github.com/tklauser/numcpus v0.3.0 github.com/tmc/grpc-websocket-proxy => github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5 github.com/tv42/httpunix => github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926 github.com/uber/jaeger-client-go => github.com/uber/jaeger-client-go v2.23.0+incompatible @@ -813,6 +821,7 @@ replace ( kubesphere.io/client-go => ./staging/src/kubesphere.io/client-go kubesphere.io/monitoring-dashboard => kubesphere.io/monitoring-dashboard v0.2.2 rsc.io/binaryregexp => rsc.io/binaryregexp v0.2.0 + rsc.io/goversion => rsc.io/goversion v1.2.0 rsc.io/letsencrypt => rsc.io/letsencrypt v0.0.1 rsc.io/pdf => rsc.io/pdf v0.1.1 rsc.io/quote/v3 => rsc.io/quote/v3 v3.1.0 diff --git a/go.sum b/go.sum index 332a8e5e7..5d9bb6ee6 100644 --- a/go.sum +++ b/go.sum @@ -288,7 +288,6 @@ github.com/go-logr/logr v0.4.0 h1:K7/B1jt6fIBQVd4Owv2MqGQClcgf0R266+7C/QjRcLc= github.com/go-logr/logr v0.4.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= github.com/go-logr/zapr v0.4.0 h1:uc1uML3hRYL9/ZZPdgHS/n8Nzo+eaYL/Efxkkamf7OM= github.com/go-logr/zapr v0.4.0/go.mod h1:tabnROwaDl0UNxkVeFRbY8bwB37GwRv0P8lg6aAiEnk= -github.com/go-ole/go-ole v1.2.5/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= github.com/go-ole/go-ole v1.2.6-0.20210915003542-8b1f7f90f6b1/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= github.com/go-openapi/analysis v0.19.10 h1:5BHISBAXOc/aJK25irLZnx2D3s6WyYaY9D4gmuz9fdE= github.com/go-openapi/analysis v0.19.10/go.mod h1:qmhS3VNFxBlquFJ0RGoDtylO9y4pgTAUNE9AEEMdlJQ= @@ -727,6 +726,8 @@ github.com/rainycape/unidecode v0.0.0-20150907023854-cb7f23ec59be/go.mod h1:MIDF github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a h1:9ZKAASQSHhDYGoxY8uLVpewe1GDZ2vu2Tr/vTdVAkFQ= github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= github.com/retailnext/hllpp v1.0.1-0.20180308014038-101a6d2f8b52/go.mod h1:RDpi1RftBQPUCDRw6SmxeaREsAaRKnOclghuzp/WRzc= +github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs= +github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro= github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= github.com/rogpeppe/go-charset v0.0.0-20180617210344-2471d30d28b4/go.mod h1:qgYeAmZ5ZIpBWTGllZSQnw97Dj+woV0toclVaRGI8pc= github.com/rogpeppe/go-internal v1.3.0 h1:RR9dF3JtopPvtkroDZuVD7qquD0bnHlKSqaQhgwt8yk= @@ -747,9 +748,7 @@ github.com/segmentio/kafka-go v0.2.0/go.mod h1:X6itGqS9L4jDletMsxZ7Dz+JFWxM6JHfP github.com/sercand/kuberesolver v2.4.0+incompatible/go.mod h1:lWF3GL0xptCB/vCiJPl/ZshwPsX/n4Y7u0CW9E7aQIQ= github.com/sergi/go-diff v1.0.0 h1:Kpca3qRNrduNnOQeazBd0ysaKrUJiIuISHxogkT9RPQ= github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= -github.com/shirou/gopsutil v0.0.0-20180427012116-c95755e4bcd7/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= github.com/shirou/gopsutil/v3 v3.21.9/go.mod h1:YWp/H8Qs5fVmf17v7JNZzA0mPJ+mS2e9JdiUF9LlKzQ= -github.com/shirou/w32 v0.0.0-20160930032740-bb4de0191aa4/go.mod h1:qsXQc7+bwAM3Q1u/4XEfrquwF8Lw7D7y5cD8CuHnfIc= github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4= github.com/shurcooL/httpfs v0.0.0-20190707220628-8d4bc4ba7749/go.mod h1:ZY1cvUeJuFPAdZ/B6v7RHavJWZn2YPVFQ1OSXhCGOkg= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= diff --git a/pkg/apiserver/apiserver.go b/pkg/apiserver/apiserver.go index 3eca33dfc..2ed17fc3d 100644 --- a/pkg/apiserver/apiserver.go +++ b/pkg/apiserver/apiserver.go @@ -41,6 +41,7 @@ import ( clusterv1alpha1 "kubesphere.io/api/cluster/v1alpha1" iamv1alpha2 "kubesphere.io/api/iam/v1alpha2" notificationv2beta1 "kubesphere.io/api/notification/v2beta1" + notificationv2beta2 "kubesphere.io/api/notification/v2beta2" tenantv1alpha1 "kubesphere.io/api/tenant/v1alpha1" typesv1beta1 "kubesphere.io/api/types/v1beta1" runtimecache "sigs.k8s.io/controller-runtime/pkg/cache" @@ -268,7 +269,8 @@ func (s *APIServer) installKubeSphereAPIs(stopCh <-chan struct{}) { urlruntime.Must(edgeruntimev1alpha1.AddToContainer(s.container, s.Config.EdgeRuntimeOptions.Endpoint)) urlruntime.Must(notificationkapisv2beta1.AddToContainer(s.container, s.InformerFactory, s.KubernetesClient.Kubernetes(), s.KubernetesClient.KubeSphere())) - urlruntime.Must(notificationkapisv2beta2.AddToContainer(s.container, s.Config.NotificationOptions)) + urlruntime.Must(notificationkapisv2beta2.AddToContainer(s.container, s.InformerFactory, s.KubernetesClient.Kubernetes(), + s.KubernetesClient.KubeSphere(), s.Config.NotificationOptions)) urlruntime.Must(gatewayv1alpha1.AddToContainer(s.container, s.Config.GatewayOptions, s.RuntimeCache, s.RuntimeClient, s.InformerFactory, s.KubernetesClient.Kubernetes(), s.LoggingClient)) } @@ -320,6 +322,10 @@ func (s *APIServer) buildHandlerChain(stopCh <-chan struct{}) { resourcev1alpha3.Resource(clusterv1alpha1.ResourcesPluralCluster), notificationv2beta1.Resource(notificationv2beta1.ResourcesPluralConfig), notificationv2beta1.Resource(notificationv2beta1.ResourcesPluralReceiver), + notificationv2beta2.Resource(notificationv2beta2.ResourcesPluralConfig), + notificationv2beta2.Resource(notificationv2beta2.ResourcesPluralReceiver), + notificationv2beta2.Resource(notificationv2beta2.ResourcesPluralRouter), + notificationv2beta2.Resource(notificationv2beta2.ResourcesPluralSilence), }, } @@ -498,6 +504,12 @@ func (s *APIServer) waitForResourceSync(ctx context.Context) error { notificationv2beta1.ResourcesPluralConfig, notificationv2beta1.ResourcesPluralReceiver, }, + {Group: "notification.kubesphere.io", Version: "v2beta2"}: { + notificationv2beta2.ResourcesPluralConfig, + notificationv2beta2.ResourcesPluralReceiver, + notificationv2beta2.ResourcesPluralRouter, + notificationv2beta2.ResourcesPluralSilence, + }, } // skip caching devops resources if devops not enabled diff --git a/pkg/client/clientset/versioned/clientset.go b/pkg/client/clientset/versioned/clientset.go index f70e1ce8d..906e91d39 100644 --- a/pkg/client/clientset/versioned/clientset.go +++ b/pkg/client/clientset/versioned/clientset.go @@ -32,12 +32,14 @@ import ( iamv1alpha2 "kubesphere.io/kubesphere/pkg/client/clientset/versioned/typed/iam/v1alpha2" networkv1alpha1 "kubesphere.io/kubesphere/pkg/client/clientset/versioned/typed/network/v1alpha1" notificationv2beta1 "kubesphere.io/kubesphere/pkg/client/clientset/versioned/typed/notification/v2beta1" + notificationv2beta2 "kubesphere.io/kubesphere/pkg/client/clientset/versioned/typed/notification/v2beta2" quotav1alpha2 "kubesphere.io/kubesphere/pkg/client/clientset/versioned/typed/quota/v1alpha2" servicemeshv1alpha2 "kubesphere.io/kubesphere/pkg/client/clientset/versioned/typed/servicemesh/v1alpha2" storagev1alpha1 "kubesphere.io/kubesphere/pkg/client/clientset/versioned/typed/storage/v1alpha1" tenantv1alpha1 "kubesphere.io/kubesphere/pkg/client/clientset/versioned/typed/tenant/v1alpha1" tenantv1alpha2 "kubesphere.io/kubesphere/pkg/client/clientset/versioned/typed/tenant/v1alpha2" typesv1beta1 "kubesphere.io/kubesphere/pkg/client/clientset/versioned/typed/types/v1beta1" + typesv1beta2 "kubesphere.io/kubesphere/pkg/client/clientset/versioned/typed/types/v1beta2" ) type Interface interface { @@ -50,12 +52,14 @@ type Interface interface { IamV1alpha2() iamv1alpha2.IamV1alpha2Interface NetworkV1alpha1() networkv1alpha1.NetworkV1alpha1Interface NotificationV2beta1() notificationv2beta1.NotificationV2beta1Interface + NotificationV2beta2() notificationv2beta2.NotificationV2beta2Interface QuotaV1alpha2() quotav1alpha2.QuotaV1alpha2Interface ServicemeshV1alpha2() servicemeshv1alpha2.ServicemeshV1alpha2Interface StorageV1alpha1() storagev1alpha1.StorageV1alpha1Interface TenantV1alpha1() tenantv1alpha1.TenantV1alpha1Interface TenantV1alpha2() tenantv1alpha2.TenantV1alpha2Interface TypesV1beta1() typesv1beta1.TypesV1beta1Interface + TypesV1beta2() typesv1beta2.TypesV1beta2Interface } // Clientset contains the clients for groups. Each group has exactly one @@ -70,12 +74,14 @@ type Clientset struct { iamV1alpha2 *iamv1alpha2.IamV1alpha2Client networkV1alpha1 *networkv1alpha1.NetworkV1alpha1Client notificationV2beta1 *notificationv2beta1.NotificationV2beta1Client + notificationV2beta2 *notificationv2beta2.NotificationV2beta2Client quotaV1alpha2 *quotav1alpha2.QuotaV1alpha2Client servicemeshV1alpha2 *servicemeshv1alpha2.ServicemeshV1alpha2Client storageV1alpha1 *storagev1alpha1.StorageV1alpha1Client tenantV1alpha1 *tenantv1alpha1.TenantV1alpha1Client tenantV1alpha2 *tenantv1alpha2.TenantV1alpha2Client typesV1beta1 *typesv1beta1.TypesV1beta1Client + typesV1beta2 *typesv1beta2.TypesV1beta2Client } // ApplicationV1alpha1 retrieves the ApplicationV1alpha1Client @@ -118,6 +124,11 @@ func (c *Clientset) NotificationV2beta1() notificationv2beta1.NotificationV2beta return c.notificationV2beta1 } +// NotificationV2beta2 retrieves the NotificationV2beta2Client +func (c *Clientset) NotificationV2beta2() notificationv2beta2.NotificationV2beta2Interface { + return c.notificationV2beta2 +} + // QuotaV1alpha2 retrieves the QuotaV1alpha2Client func (c *Clientset) QuotaV1alpha2() quotav1alpha2.QuotaV1alpha2Interface { return c.quotaV1alpha2 @@ -148,6 +159,11 @@ func (c *Clientset) TypesV1beta1() typesv1beta1.TypesV1beta1Interface { return c.typesV1beta1 } +// TypesV1beta2 retrieves the TypesV1beta2Client +func (c *Clientset) TypesV1beta2() typesv1beta2.TypesV1beta2Interface { + return c.typesV1beta2 +} + // Discovery retrieves the DiscoveryClient func (c *Clientset) Discovery() discovery.DiscoveryInterface { if c == nil { @@ -201,6 +217,10 @@ func NewForConfig(c *rest.Config) (*Clientset, error) { if err != nil { return nil, err } + cs.notificationV2beta2, err = notificationv2beta2.NewForConfig(&configShallowCopy) + if err != nil { + return nil, err + } cs.quotaV1alpha2, err = quotav1alpha2.NewForConfig(&configShallowCopy) if err != nil { return nil, err @@ -225,6 +245,10 @@ func NewForConfig(c *rest.Config) (*Clientset, error) { if err != nil { return nil, err } + cs.typesV1beta2, err = typesv1beta2.NewForConfig(&configShallowCopy) + if err != nil { + return nil, err + } cs.DiscoveryClient, err = discovery.NewDiscoveryClientForConfig(&configShallowCopy) if err != nil { @@ -245,12 +269,14 @@ func NewForConfigOrDie(c *rest.Config) *Clientset { cs.iamV1alpha2 = iamv1alpha2.NewForConfigOrDie(c) cs.networkV1alpha1 = networkv1alpha1.NewForConfigOrDie(c) cs.notificationV2beta1 = notificationv2beta1.NewForConfigOrDie(c) + cs.notificationV2beta2 = notificationv2beta2.NewForConfigOrDie(c) cs.quotaV1alpha2 = quotav1alpha2.NewForConfigOrDie(c) cs.servicemeshV1alpha2 = servicemeshv1alpha2.NewForConfigOrDie(c) cs.storageV1alpha1 = storagev1alpha1.NewForConfigOrDie(c) cs.tenantV1alpha1 = tenantv1alpha1.NewForConfigOrDie(c) cs.tenantV1alpha2 = tenantv1alpha2.NewForConfigOrDie(c) cs.typesV1beta1 = typesv1beta1.NewForConfigOrDie(c) + cs.typesV1beta2 = typesv1beta2.NewForConfigOrDie(c) cs.DiscoveryClient = discovery.NewDiscoveryClientForConfigOrDie(c) return &cs @@ -267,12 +293,14 @@ func New(c rest.Interface) *Clientset { cs.iamV1alpha2 = iamv1alpha2.New(c) cs.networkV1alpha1 = networkv1alpha1.New(c) cs.notificationV2beta1 = notificationv2beta1.New(c) + cs.notificationV2beta2 = notificationv2beta2.New(c) cs.quotaV1alpha2 = quotav1alpha2.New(c) cs.servicemeshV1alpha2 = servicemeshv1alpha2.New(c) cs.storageV1alpha1 = storagev1alpha1.New(c) cs.tenantV1alpha1 = tenantv1alpha1.New(c) cs.tenantV1alpha2 = tenantv1alpha2.New(c) cs.typesV1beta1 = typesv1beta1.New(c) + cs.typesV1beta2 = typesv1beta2.New(c) cs.DiscoveryClient = discovery.NewDiscoveryClient(c) return &cs diff --git a/pkg/client/clientset/versioned/fake/clientset_generated.go b/pkg/client/clientset/versioned/fake/clientset_generated.go index 09f5eb0bc..cb3224072 100644 --- a/pkg/client/clientset/versioned/fake/clientset_generated.go +++ b/pkg/client/clientset/versioned/fake/clientset_generated.go @@ -41,6 +41,8 @@ import ( fakenetworkv1alpha1 "kubesphere.io/kubesphere/pkg/client/clientset/versioned/typed/network/v1alpha1/fake" notificationv2beta1 "kubesphere.io/kubesphere/pkg/client/clientset/versioned/typed/notification/v2beta1" fakenotificationv2beta1 "kubesphere.io/kubesphere/pkg/client/clientset/versioned/typed/notification/v2beta1/fake" + notificationv2beta2 "kubesphere.io/kubesphere/pkg/client/clientset/versioned/typed/notification/v2beta2" + fakenotificationv2beta2 "kubesphere.io/kubesphere/pkg/client/clientset/versioned/typed/notification/v2beta2/fake" quotav1alpha2 "kubesphere.io/kubesphere/pkg/client/clientset/versioned/typed/quota/v1alpha2" fakequotav1alpha2 "kubesphere.io/kubesphere/pkg/client/clientset/versioned/typed/quota/v1alpha2/fake" servicemeshv1alpha2 "kubesphere.io/kubesphere/pkg/client/clientset/versioned/typed/servicemesh/v1alpha2" @@ -53,6 +55,8 @@ import ( faketenantv1alpha2 "kubesphere.io/kubesphere/pkg/client/clientset/versioned/typed/tenant/v1alpha2/fake" typesv1beta1 "kubesphere.io/kubesphere/pkg/client/clientset/versioned/typed/types/v1beta1" faketypesv1beta1 "kubesphere.io/kubesphere/pkg/client/clientset/versioned/typed/types/v1beta1/fake" + typesv1beta2 "kubesphere.io/kubesphere/pkg/client/clientset/versioned/typed/types/v1beta2" + faketypesv1beta2 "kubesphere.io/kubesphere/pkg/client/clientset/versioned/typed/types/v1beta2/fake" ) // NewSimpleClientset returns a clientset that will respond with the provided objects. @@ -142,6 +146,11 @@ func (c *Clientset) NotificationV2beta1() notificationv2beta1.NotificationV2beta return &fakenotificationv2beta1.FakeNotificationV2beta1{Fake: &c.Fake} } +// NotificationV2beta2 retrieves the NotificationV2beta2Client +func (c *Clientset) NotificationV2beta2() notificationv2beta2.NotificationV2beta2Interface { + return &fakenotificationv2beta2.FakeNotificationV2beta2{Fake: &c.Fake} +} + // QuotaV1alpha2 retrieves the QuotaV1alpha2Client func (c *Clientset) QuotaV1alpha2() quotav1alpha2.QuotaV1alpha2Interface { return &fakequotav1alpha2.FakeQuotaV1alpha2{Fake: &c.Fake} @@ -171,3 +180,8 @@ func (c *Clientset) TenantV1alpha2() tenantv1alpha2.TenantV1alpha2Interface { func (c *Clientset) TypesV1beta1() typesv1beta1.TypesV1beta1Interface { return &faketypesv1beta1.FakeTypesV1beta1{Fake: &c.Fake} } + +// TypesV1beta2 retrieves the TypesV1beta2Client +func (c *Clientset) TypesV1beta2() typesv1beta2.TypesV1beta2Interface { + return &faketypesv1beta2.FakeTypesV1beta2{Fake: &c.Fake} +} diff --git a/pkg/client/clientset/versioned/fake/register.go b/pkg/client/clientset/versioned/fake/register.go index f1b13954c..e03b59a5f 100644 --- a/pkg/client/clientset/versioned/fake/register.go +++ b/pkg/client/clientset/versioned/fake/register.go @@ -32,12 +32,14 @@ import ( iamv1alpha2 "kubesphere.io/api/iam/v1alpha2" networkv1alpha1 "kubesphere.io/api/network/v1alpha1" notificationv2beta1 "kubesphere.io/api/notification/v2beta1" + notificationv2beta2 "kubesphere.io/api/notification/v2beta2" quotav1alpha2 "kubesphere.io/api/quota/v1alpha2" servicemeshv1alpha2 "kubesphere.io/api/servicemesh/v1alpha2" storagev1alpha1 "kubesphere.io/api/storage/v1alpha1" tenantv1alpha1 "kubesphere.io/api/tenant/v1alpha1" tenantv1alpha2 "kubesphere.io/api/tenant/v1alpha2" typesv1beta1 "kubesphere.io/api/types/v1beta1" + typesv1beta2 "kubesphere.io/api/types/v1beta2" ) var scheme = runtime.NewScheme() @@ -52,12 +54,14 @@ var localSchemeBuilder = runtime.SchemeBuilder{ iamv1alpha2.AddToScheme, networkv1alpha1.AddToScheme, notificationv2beta1.AddToScheme, + notificationv2beta2.AddToScheme, quotav1alpha2.AddToScheme, servicemeshv1alpha2.AddToScheme, storagev1alpha1.AddToScheme, tenantv1alpha1.AddToScheme, tenantv1alpha2.AddToScheme, typesv1beta1.AddToScheme, + typesv1beta2.AddToScheme, } // AddToScheme adds all types of this clientset into the given scheme. This allows composition diff --git a/pkg/client/clientset/versioned/scheme/register.go b/pkg/client/clientset/versioned/scheme/register.go index a6ecfed2e..b28b221e8 100644 --- a/pkg/client/clientset/versioned/scheme/register.go +++ b/pkg/client/clientset/versioned/scheme/register.go @@ -32,12 +32,14 @@ import ( iamv1alpha2 "kubesphere.io/api/iam/v1alpha2" networkv1alpha1 "kubesphere.io/api/network/v1alpha1" notificationv2beta1 "kubesphere.io/api/notification/v2beta1" + notificationv2beta2 "kubesphere.io/api/notification/v2beta2" quotav1alpha2 "kubesphere.io/api/quota/v1alpha2" servicemeshv1alpha2 "kubesphere.io/api/servicemesh/v1alpha2" storagev1alpha1 "kubesphere.io/api/storage/v1alpha1" tenantv1alpha1 "kubesphere.io/api/tenant/v1alpha1" tenantv1alpha2 "kubesphere.io/api/tenant/v1alpha2" typesv1beta1 "kubesphere.io/api/types/v1beta1" + typesv1beta2 "kubesphere.io/api/types/v1beta2" ) var Scheme = runtime.NewScheme() @@ -52,12 +54,14 @@ var localSchemeBuilder = runtime.SchemeBuilder{ iamv1alpha2.AddToScheme, networkv1alpha1.AddToScheme, notificationv2beta1.AddToScheme, + notificationv2beta2.AddToScheme, quotav1alpha2.AddToScheme, servicemeshv1alpha2.AddToScheme, storagev1alpha1.AddToScheme, tenantv1alpha1.AddToScheme, tenantv1alpha2.AddToScheme, typesv1beta1.AddToScheme, + typesv1beta2.AddToScheme, } // AddToScheme adds all types of this clientset into the given scheme. This allows composition diff --git a/pkg/client/clientset/versioned/typed/notification/v2beta2/config.go b/pkg/client/clientset/versioned/typed/notification/v2beta2/config.go new file mode 100644 index 000000000..a4510b491 --- /dev/null +++ b/pkg/client/clientset/versioned/typed/notification/v2beta2/config.go @@ -0,0 +1,184 @@ +/* +Copyright 2020 The KubeSphere Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package v2beta2 + +import ( + "context" + "time" + + 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" + v2beta2 "kubesphere.io/api/notification/v2beta2" + scheme "kubesphere.io/kubesphere/pkg/client/clientset/versioned/scheme" +) + +// ConfigsGetter has a method to return a ConfigInterface. +// A group's client should implement this interface. +type ConfigsGetter interface { + Configs() ConfigInterface +} + +// ConfigInterface has methods to work with Config resources. +type ConfigInterface interface { + Create(ctx context.Context, config *v2beta2.Config, opts v1.CreateOptions) (*v2beta2.Config, error) + Update(ctx context.Context, config *v2beta2.Config, opts v1.UpdateOptions) (*v2beta2.Config, error) + UpdateStatus(ctx context.Context, config *v2beta2.Config, opts v1.UpdateOptions) (*v2beta2.Config, 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) (*v2beta2.Config, error) + List(ctx context.Context, opts v1.ListOptions) (*v2beta2.ConfigList, 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 *v2beta2.Config, err error) + ConfigExpansion +} + +// configs implements ConfigInterface +type configs struct { + client rest.Interface +} + +// newConfigs returns a Configs +func newConfigs(c *NotificationV2beta2Client) *configs { + return &configs{ + client: c.RESTClient(), + } +} + +// Get takes name of the config, and returns the corresponding config object, and an error if there is any. +func (c *configs) Get(ctx context.Context, name string, options v1.GetOptions) (result *v2beta2.Config, err error) { + result = &v2beta2.Config{} + err = c.client.Get(). + Resource("configs"). + Name(name). + VersionedParams(&options, scheme.ParameterCodec). + Do(ctx). + Into(result) + return +} + +// List takes label and field selectors, and returns the list of Configs that match those selectors. +func (c *configs) List(ctx context.Context, opts v1.ListOptions) (result *v2beta2.ConfigList, err error) { + var timeout time.Duration + if opts.TimeoutSeconds != nil { + timeout = time.Duration(*opts.TimeoutSeconds) * time.Second + } + result = &v2beta2.ConfigList{} + err = c.client.Get(). + Resource("configs"). + VersionedParams(&opts, scheme.ParameterCodec). + Timeout(timeout). + Do(ctx). + Into(result) + return +} + +// Watch returns a watch.Interface that watches the requested configs. +func (c *configs) 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(). + Resource("configs"). + VersionedParams(&opts, scheme.ParameterCodec). + Timeout(timeout). + Watch(ctx) +} + +// Create takes the representation of a config and creates it. Returns the server's representation of the config, and an error, if there is any. +func (c *configs) Create(ctx context.Context, config *v2beta2.Config, opts v1.CreateOptions) (result *v2beta2.Config, err error) { + result = &v2beta2.Config{} + err = c.client.Post(). + Resource("configs"). + VersionedParams(&opts, scheme.ParameterCodec). + Body(config). + Do(ctx). + Into(result) + return +} + +// Update takes the representation of a config and updates it. Returns the server's representation of the config, and an error, if there is any. +func (c *configs) Update(ctx context.Context, config *v2beta2.Config, opts v1.UpdateOptions) (result *v2beta2.Config, err error) { + result = &v2beta2.Config{} + err = c.client.Put(). + Resource("configs"). + Name(config.Name). + VersionedParams(&opts, scheme.ParameterCodec). + Body(config). + Do(ctx). + Into(result) + return +} + +// UpdateStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). +func (c *configs) UpdateStatus(ctx context.Context, config *v2beta2.Config, opts v1.UpdateOptions) (result *v2beta2.Config, err error) { + result = &v2beta2.Config{} + err = c.client.Put(). + Resource("configs"). + Name(config.Name). + SubResource("status"). + VersionedParams(&opts, scheme.ParameterCodec). + Body(config). + Do(ctx). + Into(result) + return +} + +// Delete takes name of the config and deletes it. Returns an error if one occurs. +func (c *configs) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { + return c.client.Delete(). + Resource("configs"). + Name(name). + Body(&opts). + Do(ctx). + Error() +} + +// DeleteCollection deletes a collection of objects. +func (c *configs) 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(). + Resource("configs"). + VersionedParams(&listOpts, scheme.ParameterCodec). + Timeout(timeout). + Body(&opts). + Do(ctx). + Error() +} + +// Patch applies the patch and returns the patched config. +func (c *configs) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v2beta2.Config, err error) { + result = &v2beta2.Config{} + err = c.client.Patch(pt). + Resource("configs"). + Name(name). + SubResource(subresources...). + VersionedParams(&opts, scheme.ParameterCodec). + Body(data). + Do(ctx). + Into(result) + return +} diff --git a/pkg/client/clientset/versioned/typed/notification/v2beta2/doc.go b/pkg/client/clientset/versioned/typed/notification/v2beta2/doc.go new file mode 100644 index 000000000..dca114d3a --- /dev/null +++ b/pkg/client/clientset/versioned/typed/notification/v2beta2/doc.go @@ -0,0 +1,20 @@ +/* +Copyright 2020 The KubeSphere Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +// This package has the automatically generated typed clients. +package v2beta2 diff --git a/pkg/client/clientset/versioned/typed/notification/v2beta2/fake/doc.go b/pkg/client/clientset/versioned/typed/notification/v2beta2/fake/doc.go new file mode 100644 index 000000000..7e36dbca8 --- /dev/null +++ b/pkg/client/clientset/versioned/typed/notification/v2beta2/fake/doc.go @@ -0,0 +1,20 @@ +/* +Copyright 2020 The KubeSphere Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +// Package fake has the automatically generated clients. +package fake diff --git a/pkg/client/clientset/versioned/typed/notification/v2beta2/fake/fake_config.go b/pkg/client/clientset/versioned/typed/notification/v2beta2/fake/fake_config.go new file mode 100644 index 000000000..5b4d87ee5 --- /dev/null +++ b/pkg/client/clientset/versioned/typed/notification/v2beta2/fake/fake_config.go @@ -0,0 +1,133 @@ +/* +Copyright 2020 The KubeSphere Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + "context" + + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + schema "k8s.io/apimachinery/pkg/runtime/schema" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + testing "k8s.io/client-go/testing" + v2beta2 "kubesphere.io/api/notification/v2beta2" +) + +// FakeConfigs implements ConfigInterface +type FakeConfigs struct { + Fake *FakeNotificationV2beta2 +} + +var configsResource = schema.GroupVersionResource{Group: "notification.kubesphere.io", Version: "v2beta2", Resource: "configs"} + +var configsKind = schema.GroupVersionKind{Group: "notification.kubesphere.io", Version: "v2beta2", Kind: "Config"} + +// Get takes name of the config, and returns the corresponding config object, and an error if there is any. +func (c *FakeConfigs) Get(ctx context.Context, name string, options v1.GetOptions) (result *v2beta2.Config, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootGetAction(configsResource, name), &v2beta2.Config{}) + if obj == nil { + return nil, err + } + return obj.(*v2beta2.Config), err +} + +// List takes label and field selectors, and returns the list of Configs that match those selectors. +func (c *FakeConfigs) List(ctx context.Context, opts v1.ListOptions) (result *v2beta2.ConfigList, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootListAction(configsResource, configsKind, opts), &v2beta2.ConfigList{}) + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &v2beta2.ConfigList{ListMeta: obj.(*v2beta2.ConfigList).ListMeta} + for _, item := range obj.(*v2beta2.ConfigList).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 configs. +func (c *FakeConfigs) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewRootWatchAction(configsResource, opts)) +} + +// Create takes the representation of a config and creates it. Returns the server's representation of the config, and an error, if there is any. +func (c *FakeConfigs) Create(ctx context.Context, config *v2beta2.Config, opts v1.CreateOptions) (result *v2beta2.Config, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootCreateAction(configsResource, config), &v2beta2.Config{}) + if obj == nil { + return nil, err + } + return obj.(*v2beta2.Config), err +} + +// Update takes the representation of a config and updates it. Returns the server's representation of the config, and an error, if there is any. +func (c *FakeConfigs) Update(ctx context.Context, config *v2beta2.Config, opts v1.UpdateOptions) (result *v2beta2.Config, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootUpdateAction(configsResource, config), &v2beta2.Config{}) + if obj == nil { + return nil, err + } + return obj.(*v2beta2.Config), err +} + +// UpdateStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). +func (c *FakeConfigs) UpdateStatus(ctx context.Context, config *v2beta2.Config, opts v1.UpdateOptions) (*v2beta2.Config, error) { + obj, err := c.Fake. + Invokes(testing.NewRootUpdateSubresourceAction(configsResource, "status", config), &v2beta2.Config{}) + if obj == nil { + return nil, err + } + return obj.(*v2beta2.Config), err +} + +// Delete takes name of the config and deletes it. Returns an error if one occurs. +func (c *FakeConfigs) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewRootDeleteAction(configsResource, name), &v2beta2.Config{}) + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeConfigs) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { + action := testing.NewRootDeleteCollectionAction(configsResource, listOpts) + + _, err := c.Fake.Invokes(action, &v2beta2.ConfigList{}) + return err +} + +// Patch applies the patch and returns the patched config. +func (c *FakeConfigs) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v2beta2.Config, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootPatchSubresourceAction(configsResource, name, pt, data, subresources...), &v2beta2.Config{}) + if obj == nil { + return nil, err + } + return obj.(*v2beta2.Config), err +} diff --git a/pkg/client/clientset/versioned/typed/notification/v2beta2/fake/fake_notification_client.go b/pkg/client/clientset/versioned/typed/notification/v2beta2/fake/fake_notification_client.go new file mode 100644 index 000000000..4e846b425 --- /dev/null +++ b/pkg/client/clientset/versioned/typed/notification/v2beta2/fake/fake_notification_client.go @@ -0,0 +1,52 @@ +/* +Copyright 2020 The KubeSphere Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + rest "k8s.io/client-go/rest" + testing "k8s.io/client-go/testing" + v2beta2 "kubesphere.io/kubesphere/pkg/client/clientset/versioned/typed/notification/v2beta2" +) + +type FakeNotificationV2beta2 struct { + *testing.Fake +} + +func (c *FakeNotificationV2beta2) Configs() v2beta2.ConfigInterface { + return &FakeConfigs{c} +} + +func (c *FakeNotificationV2beta2) Receivers() v2beta2.ReceiverInterface { + return &FakeReceivers{c} +} + +func (c *FakeNotificationV2beta2) Routers() v2beta2.RouterInterface { + return &FakeRouters{c} +} + +func (c *FakeNotificationV2beta2) Silences() v2beta2.SilenceInterface { + return &FakeSilences{c} +} + +// RESTClient returns a RESTClient that is used to communicate +// with API server by this client implementation. +func (c *FakeNotificationV2beta2) RESTClient() rest.Interface { + var ret *rest.RESTClient + return ret +} diff --git a/pkg/client/clientset/versioned/typed/notification/v2beta2/fake/fake_receiver.go b/pkg/client/clientset/versioned/typed/notification/v2beta2/fake/fake_receiver.go new file mode 100644 index 000000000..c9092b510 --- /dev/null +++ b/pkg/client/clientset/versioned/typed/notification/v2beta2/fake/fake_receiver.go @@ -0,0 +1,133 @@ +/* +Copyright 2020 The KubeSphere Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + "context" + + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + schema "k8s.io/apimachinery/pkg/runtime/schema" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + testing "k8s.io/client-go/testing" + v2beta2 "kubesphere.io/api/notification/v2beta2" +) + +// FakeReceivers implements ReceiverInterface +type FakeReceivers struct { + Fake *FakeNotificationV2beta2 +} + +var receiversResource = schema.GroupVersionResource{Group: "notification.kubesphere.io", Version: "v2beta2", Resource: "receivers"} + +var receiversKind = schema.GroupVersionKind{Group: "notification.kubesphere.io", Version: "v2beta2", Kind: "Receiver"} + +// Get takes name of the receiver, and returns the corresponding receiver object, and an error if there is any. +func (c *FakeReceivers) Get(ctx context.Context, name string, options v1.GetOptions) (result *v2beta2.Receiver, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootGetAction(receiversResource, name), &v2beta2.Receiver{}) + if obj == nil { + return nil, err + } + return obj.(*v2beta2.Receiver), err +} + +// List takes label and field selectors, and returns the list of Receivers that match those selectors. +func (c *FakeReceivers) List(ctx context.Context, opts v1.ListOptions) (result *v2beta2.ReceiverList, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootListAction(receiversResource, receiversKind, opts), &v2beta2.ReceiverList{}) + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &v2beta2.ReceiverList{ListMeta: obj.(*v2beta2.ReceiverList).ListMeta} + for _, item := range obj.(*v2beta2.ReceiverList).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 receivers. +func (c *FakeReceivers) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewRootWatchAction(receiversResource, opts)) +} + +// Create takes the representation of a receiver and creates it. Returns the server's representation of the receiver, and an error, if there is any. +func (c *FakeReceivers) Create(ctx context.Context, receiver *v2beta2.Receiver, opts v1.CreateOptions) (result *v2beta2.Receiver, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootCreateAction(receiversResource, receiver), &v2beta2.Receiver{}) + if obj == nil { + return nil, err + } + return obj.(*v2beta2.Receiver), err +} + +// Update takes the representation of a receiver and updates it. Returns the server's representation of the receiver, and an error, if there is any. +func (c *FakeReceivers) Update(ctx context.Context, receiver *v2beta2.Receiver, opts v1.UpdateOptions) (result *v2beta2.Receiver, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootUpdateAction(receiversResource, receiver), &v2beta2.Receiver{}) + if obj == nil { + return nil, err + } + return obj.(*v2beta2.Receiver), err +} + +// UpdateStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). +func (c *FakeReceivers) UpdateStatus(ctx context.Context, receiver *v2beta2.Receiver, opts v1.UpdateOptions) (*v2beta2.Receiver, error) { + obj, err := c.Fake. + Invokes(testing.NewRootUpdateSubresourceAction(receiversResource, "status", receiver), &v2beta2.Receiver{}) + if obj == nil { + return nil, err + } + return obj.(*v2beta2.Receiver), err +} + +// Delete takes name of the receiver and deletes it. Returns an error if one occurs. +func (c *FakeReceivers) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewRootDeleteAction(receiversResource, name), &v2beta2.Receiver{}) + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeReceivers) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { + action := testing.NewRootDeleteCollectionAction(receiversResource, listOpts) + + _, err := c.Fake.Invokes(action, &v2beta2.ReceiverList{}) + return err +} + +// Patch applies the patch and returns the patched receiver. +func (c *FakeReceivers) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v2beta2.Receiver, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootPatchSubresourceAction(receiversResource, name, pt, data, subresources...), &v2beta2.Receiver{}) + if obj == nil { + return nil, err + } + return obj.(*v2beta2.Receiver), err +} diff --git a/pkg/client/clientset/versioned/typed/notification/v2beta2/fake/fake_router.go b/pkg/client/clientset/versioned/typed/notification/v2beta2/fake/fake_router.go new file mode 100644 index 000000000..3fa3773ef --- /dev/null +++ b/pkg/client/clientset/versioned/typed/notification/v2beta2/fake/fake_router.go @@ -0,0 +1,133 @@ +/* +Copyright 2020 The KubeSphere Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + "context" + + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + schema "k8s.io/apimachinery/pkg/runtime/schema" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + testing "k8s.io/client-go/testing" + v2beta2 "kubesphere.io/api/notification/v2beta2" +) + +// FakeRouters implements RouterInterface +type FakeRouters struct { + Fake *FakeNotificationV2beta2 +} + +var routersResource = schema.GroupVersionResource{Group: "notification.kubesphere.io", Version: "v2beta2", Resource: "routers"} + +var routersKind = schema.GroupVersionKind{Group: "notification.kubesphere.io", Version: "v2beta2", Kind: "Router"} + +// Get takes name of the router, and returns the corresponding router object, and an error if there is any. +func (c *FakeRouters) Get(ctx context.Context, name string, options v1.GetOptions) (result *v2beta2.Router, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootGetAction(routersResource, name), &v2beta2.Router{}) + if obj == nil { + return nil, err + } + return obj.(*v2beta2.Router), err +} + +// List takes label and field selectors, and returns the list of Routers that match those selectors. +func (c *FakeRouters) List(ctx context.Context, opts v1.ListOptions) (result *v2beta2.RouterList, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootListAction(routersResource, routersKind, opts), &v2beta2.RouterList{}) + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &v2beta2.RouterList{ListMeta: obj.(*v2beta2.RouterList).ListMeta} + for _, item := range obj.(*v2beta2.RouterList).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 routers. +func (c *FakeRouters) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewRootWatchAction(routersResource, opts)) +} + +// Create takes the representation of a router and creates it. Returns the server's representation of the router, and an error, if there is any. +func (c *FakeRouters) Create(ctx context.Context, router *v2beta2.Router, opts v1.CreateOptions) (result *v2beta2.Router, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootCreateAction(routersResource, router), &v2beta2.Router{}) + if obj == nil { + return nil, err + } + return obj.(*v2beta2.Router), err +} + +// Update takes the representation of a router and updates it. Returns the server's representation of the router, and an error, if there is any. +func (c *FakeRouters) Update(ctx context.Context, router *v2beta2.Router, opts v1.UpdateOptions) (result *v2beta2.Router, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootUpdateAction(routersResource, router), &v2beta2.Router{}) + if obj == nil { + return nil, err + } + return obj.(*v2beta2.Router), err +} + +// UpdateStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). +func (c *FakeRouters) UpdateStatus(ctx context.Context, router *v2beta2.Router, opts v1.UpdateOptions) (*v2beta2.Router, error) { + obj, err := c.Fake. + Invokes(testing.NewRootUpdateSubresourceAction(routersResource, "status", router), &v2beta2.Router{}) + if obj == nil { + return nil, err + } + return obj.(*v2beta2.Router), err +} + +// Delete takes name of the router and deletes it. Returns an error if one occurs. +func (c *FakeRouters) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewRootDeleteAction(routersResource, name), &v2beta2.Router{}) + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeRouters) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { + action := testing.NewRootDeleteCollectionAction(routersResource, listOpts) + + _, err := c.Fake.Invokes(action, &v2beta2.RouterList{}) + return err +} + +// Patch applies the patch and returns the patched router. +func (c *FakeRouters) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v2beta2.Router, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootPatchSubresourceAction(routersResource, name, pt, data, subresources...), &v2beta2.Router{}) + if obj == nil { + return nil, err + } + return obj.(*v2beta2.Router), err +} diff --git a/pkg/client/clientset/versioned/typed/notification/v2beta2/fake/fake_silence.go b/pkg/client/clientset/versioned/typed/notification/v2beta2/fake/fake_silence.go new file mode 100644 index 000000000..f7bcb03fc --- /dev/null +++ b/pkg/client/clientset/versioned/typed/notification/v2beta2/fake/fake_silence.go @@ -0,0 +1,133 @@ +/* +Copyright 2020 The KubeSphere Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + "context" + + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + schema "k8s.io/apimachinery/pkg/runtime/schema" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + testing "k8s.io/client-go/testing" + v2beta2 "kubesphere.io/api/notification/v2beta2" +) + +// FakeSilences implements SilenceInterface +type FakeSilences struct { + Fake *FakeNotificationV2beta2 +} + +var silencesResource = schema.GroupVersionResource{Group: "notification.kubesphere.io", Version: "v2beta2", Resource: "silences"} + +var silencesKind = schema.GroupVersionKind{Group: "notification.kubesphere.io", Version: "v2beta2", Kind: "Silence"} + +// Get takes name of the silence, and returns the corresponding silence object, and an error if there is any. +func (c *FakeSilences) Get(ctx context.Context, name string, options v1.GetOptions) (result *v2beta2.Silence, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootGetAction(silencesResource, name), &v2beta2.Silence{}) + if obj == nil { + return nil, err + } + return obj.(*v2beta2.Silence), err +} + +// List takes label and field selectors, and returns the list of Silences that match those selectors. +func (c *FakeSilences) List(ctx context.Context, opts v1.ListOptions) (result *v2beta2.SilenceList, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootListAction(silencesResource, silencesKind, opts), &v2beta2.SilenceList{}) + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &v2beta2.SilenceList{ListMeta: obj.(*v2beta2.SilenceList).ListMeta} + for _, item := range obj.(*v2beta2.SilenceList).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 silences. +func (c *FakeSilences) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewRootWatchAction(silencesResource, opts)) +} + +// Create takes the representation of a silence and creates it. Returns the server's representation of the silence, and an error, if there is any. +func (c *FakeSilences) Create(ctx context.Context, silence *v2beta2.Silence, opts v1.CreateOptions) (result *v2beta2.Silence, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootCreateAction(silencesResource, silence), &v2beta2.Silence{}) + if obj == nil { + return nil, err + } + return obj.(*v2beta2.Silence), err +} + +// Update takes the representation of a silence and updates it. Returns the server's representation of the silence, and an error, if there is any. +func (c *FakeSilences) Update(ctx context.Context, silence *v2beta2.Silence, opts v1.UpdateOptions) (result *v2beta2.Silence, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootUpdateAction(silencesResource, silence), &v2beta2.Silence{}) + if obj == nil { + return nil, err + } + return obj.(*v2beta2.Silence), err +} + +// UpdateStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). +func (c *FakeSilences) UpdateStatus(ctx context.Context, silence *v2beta2.Silence, opts v1.UpdateOptions) (*v2beta2.Silence, error) { + obj, err := c.Fake. + Invokes(testing.NewRootUpdateSubresourceAction(silencesResource, "status", silence), &v2beta2.Silence{}) + if obj == nil { + return nil, err + } + return obj.(*v2beta2.Silence), err +} + +// Delete takes name of the silence and deletes it. Returns an error if one occurs. +func (c *FakeSilences) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewRootDeleteAction(silencesResource, name), &v2beta2.Silence{}) + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeSilences) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { + action := testing.NewRootDeleteCollectionAction(silencesResource, listOpts) + + _, err := c.Fake.Invokes(action, &v2beta2.SilenceList{}) + return err +} + +// Patch applies the patch and returns the patched silence. +func (c *FakeSilences) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v2beta2.Silence, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootPatchSubresourceAction(silencesResource, name, pt, data, subresources...), &v2beta2.Silence{}) + if obj == nil { + return nil, err + } + return obj.(*v2beta2.Silence), err +} diff --git a/pkg/client/clientset/versioned/typed/notification/v2beta2/generated_expansion.go b/pkg/client/clientset/versioned/typed/notification/v2beta2/generated_expansion.go new file mode 100644 index 000000000..9f96706e7 --- /dev/null +++ b/pkg/client/clientset/versioned/typed/notification/v2beta2/generated_expansion.go @@ -0,0 +1,27 @@ +/* +Copyright 2020 The KubeSphere Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package v2beta2 + +type ConfigExpansion interface{} + +type ReceiverExpansion interface{} + +type RouterExpansion interface{} + +type SilenceExpansion interface{} diff --git a/pkg/client/clientset/versioned/typed/notification/v2beta2/notification_client.go b/pkg/client/clientset/versioned/typed/notification/v2beta2/notification_client.go new file mode 100644 index 000000000..c8c4df025 --- /dev/null +++ b/pkg/client/clientset/versioned/typed/notification/v2beta2/notification_client.go @@ -0,0 +1,104 @@ +/* +Copyright 2020 The KubeSphere Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package v2beta2 + +import ( + rest "k8s.io/client-go/rest" + v2beta2 "kubesphere.io/api/notification/v2beta2" + "kubesphere.io/kubesphere/pkg/client/clientset/versioned/scheme" +) + +type NotificationV2beta2Interface interface { + RESTClient() rest.Interface + ConfigsGetter + ReceiversGetter + RoutersGetter + SilencesGetter +} + +// NotificationV2beta2Client is used to interact with features provided by the notification.kubesphere.io group. +type NotificationV2beta2Client struct { + restClient rest.Interface +} + +func (c *NotificationV2beta2Client) Configs() ConfigInterface { + return newConfigs(c) +} + +func (c *NotificationV2beta2Client) Receivers() ReceiverInterface { + return newReceivers(c) +} + +func (c *NotificationV2beta2Client) Routers() RouterInterface { + return newRouters(c) +} + +func (c *NotificationV2beta2Client) Silences() SilenceInterface { + return newSilences(c) +} + +// NewForConfig creates a new NotificationV2beta2Client for the given config. +func NewForConfig(c *rest.Config) (*NotificationV2beta2Client, error) { + config := *c + if err := setConfigDefaults(&config); err != nil { + return nil, err + } + client, err := rest.RESTClientFor(&config) + if err != nil { + return nil, err + } + return &NotificationV2beta2Client{client}, nil +} + +// NewForConfigOrDie creates a new NotificationV2beta2Client for the given config and +// panics if there is an error in the config. +func NewForConfigOrDie(c *rest.Config) *NotificationV2beta2Client { + client, err := NewForConfig(c) + if err != nil { + panic(err) + } + return client +} + +// New creates a new NotificationV2beta2Client for the given RESTClient. +func New(c rest.Interface) *NotificationV2beta2Client { + return &NotificationV2beta2Client{c} +} + +func setConfigDefaults(config *rest.Config) error { + gv := v2beta2.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 *NotificationV2beta2Client) RESTClient() rest.Interface { + if c == nil { + return nil + } + return c.restClient +} diff --git a/pkg/client/clientset/versioned/typed/notification/v2beta2/receiver.go b/pkg/client/clientset/versioned/typed/notification/v2beta2/receiver.go new file mode 100644 index 000000000..645d223f9 --- /dev/null +++ b/pkg/client/clientset/versioned/typed/notification/v2beta2/receiver.go @@ -0,0 +1,184 @@ +/* +Copyright 2020 The KubeSphere Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package v2beta2 + +import ( + "context" + "time" + + 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" + v2beta2 "kubesphere.io/api/notification/v2beta2" + scheme "kubesphere.io/kubesphere/pkg/client/clientset/versioned/scheme" +) + +// ReceiversGetter has a method to return a ReceiverInterface. +// A group's client should implement this interface. +type ReceiversGetter interface { + Receivers() ReceiverInterface +} + +// ReceiverInterface has methods to work with Receiver resources. +type ReceiverInterface interface { + Create(ctx context.Context, receiver *v2beta2.Receiver, opts v1.CreateOptions) (*v2beta2.Receiver, error) + Update(ctx context.Context, receiver *v2beta2.Receiver, opts v1.UpdateOptions) (*v2beta2.Receiver, error) + UpdateStatus(ctx context.Context, receiver *v2beta2.Receiver, opts v1.UpdateOptions) (*v2beta2.Receiver, 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) (*v2beta2.Receiver, error) + List(ctx context.Context, opts v1.ListOptions) (*v2beta2.ReceiverList, 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 *v2beta2.Receiver, err error) + ReceiverExpansion +} + +// receivers implements ReceiverInterface +type receivers struct { + client rest.Interface +} + +// newReceivers returns a Receivers +func newReceivers(c *NotificationV2beta2Client) *receivers { + return &receivers{ + client: c.RESTClient(), + } +} + +// Get takes name of the receiver, and returns the corresponding receiver object, and an error if there is any. +func (c *receivers) Get(ctx context.Context, name string, options v1.GetOptions) (result *v2beta2.Receiver, err error) { + result = &v2beta2.Receiver{} + err = c.client.Get(). + Resource("receivers"). + Name(name). + VersionedParams(&options, scheme.ParameterCodec). + Do(ctx). + Into(result) + return +} + +// List takes label and field selectors, and returns the list of Receivers that match those selectors. +func (c *receivers) List(ctx context.Context, opts v1.ListOptions) (result *v2beta2.ReceiverList, err error) { + var timeout time.Duration + if opts.TimeoutSeconds != nil { + timeout = time.Duration(*opts.TimeoutSeconds) * time.Second + } + result = &v2beta2.ReceiverList{} + err = c.client.Get(). + Resource("receivers"). + VersionedParams(&opts, scheme.ParameterCodec). + Timeout(timeout). + Do(ctx). + Into(result) + return +} + +// Watch returns a watch.Interface that watches the requested receivers. +func (c *receivers) 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(). + Resource("receivers"). + VersionedParams(&opts, scheme.ParameterCodec). + Timeout(timeout). + Watch(ctx) +} + +// Create takes the representation of a receiver and creates it. Returns the server's representation of the receiver, and an error, if there is any. +func (c *receivers) Create(ctx context.Context, receiver *v2beta2.Receiver, opts v1.CreateOptions) (result *v2beta2.Receiver, err error) { + result = &v2beta2.Receiver{} + err = c.client.Post(). + Resource("receivers"). + VersionedParams(&opts, scheme.ParameterCodec). + Body(receiver). + Do(ctx). + Into(result) + return +} + +// Update takes the representation of a receiver and updates it. Returns the server's representation of the receiver, and an error, if there is any. +func (c *receivers) Update(ctx context.Context, receiver *v2beta2.Receiver, opts v1.UpdateOptions) (result *v2beta2.Receiver, err error) { + result = &v2beta2.Receiver{} + err = c.client.Put(). + Resource("receivers"). + Name(receiver.Name). + VersionedParams(&opts, scheme.ParameterCodec). + Body(receiver). + Do(ctx). + Into(result) + return +} + +// UpdateStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). +func (c *receivers) UpdateStatus(ctx context.Context, receiver *v2beta2.Receiver, opts v1.UpdateOptions) (result *v2beta2.Receiver, err error) { + result = &v2beta2.Receiver{} + err = c.client.Put(). + Resource("receivers"). + Name(receiver.Name). + SubResource("status"). + VersionedParams(&opts, scheme.ParameterCodec). + Body(receiver). + Do(ctx). + Into(result) + return +} + +// Delete takes name of the receiver and deletes it. Returns an error if one occurs. +func (c *receivers) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { + return c.client.Delete(). + Resource("receivers"). + Name(name). + Body(&opts). + Do(ctx). + Error() +} + +// DeleteCollection deletes a collection of objects. +func (c *receivers) 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(). + Resource("receivers"). + VersionedParams(&listOpts, scheme.ParameterCodec). + Timeout(timeout). + Body(&opts). + Do(ctx). + Error() +} + +// Patch applies the patch and returns the patched receiver. +func (c *receivers) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v2beta2.Receiver, err error) { + result = &v2beta2.Receiver{} + err = c.client.Patch(pt). + Resource("receivers"). + Name(name). + SubResource(subresources...). + VersionedParams(&opts, scheme.ParameterCodec). + Body(data). + Do(ctx). + Into(result) + return +} diff --git a/pkg/client/clientset/versioned/typed/notification/v2beta2/router.go b/pkg/client/clientset/versioned/typed/notification/v2beta2/router.go new file mode 100644 index 000000000..fc5a8e468 --- /dev/null +++ b/pkg/client/clientset/versioned/typed/notification/v2beta2/router.go @@ -0,0 +1,184 @@ +/* +Copyright 2020 The KubeSphere Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package v2beta2 + +import ( + "context" + "time" + + 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" + v2beta2 "kubesphere.io/api/notification/v2beta2" + scheme "kubesphere.io/kubesphere/pkg/client/clientset/versioned/scheme" +) + +// RoutersGetter has a method to return a RouterInterface. +// A group's client should implement this interface. +type RoutersGetter interface { + Routers() RouterInterface +} + +// RouterInterface has methods to work with Router resources. +type RouterInterface interface { + Create(ctx context.Context, router *v2beta2.Router, opts v1.CreateOptions) (*v2beta2.Router, error) + Update(ctx context.Context, router *v2beta2.Router, opts v1.UpdateOptions) (*v2beta2.Router, error) + UpdateStatus(ctx context.Context, router *v2beta2.Router, opts v1.UpdateOptions) (*v2beta2.Router, 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) (*v2beta2.Router, error) + List(ctx context.Context, opts v1.ListOptions) (*v2beta2.RouterList, 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 *v2beta2.Router, err error) + RouterExpansion +} + +// routers implements RouterInterface +type routers struct { + client rest.Interface +} + +// newRouters returns a Routers +func newRouters(c *NotificationV2beta2Client) *routers { + return &routers{ + client: c.RESTClient(), + } +} + +// Get takes name of the router, and returns the corresponding router object, and an error if there is any. +func (c *routers) Get(ctx context.Context, name string, options v1.GetOptions) (result *v2beta2.Router, err error) { + result = &v2beta2.Router{} + err = c.client.Get(). + Resource("routers"). + Name(name). + VersionedParams(&options, scheme.ParameterCodec). + Do(ctx). + Into(result) + return +} + +// List takes label and field selectors, and returns the list of Routers that match those selectors. +func (c *routers) List(ctx context.Context, opts v1.ListOptions) (result *v2beta2.RouterList, err error) { + var timeout time.Duration + if opts.TimeoutSeconds != nil { + timeout = time.Duration(*opts.TimeoutSeconds) * time.Second + } + result = &v2beta2.RouterList{} + err = c.client.Get(). + Resource("routers"). + VersionedParams(&opts, scheme.ParameterCodec). + Timeout(timeout). + Do(ctx). + Into(result) + return +} + +// Watch returns a watch.Interface that watches the requested routers. +func (c *routers) 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(). + Resource("routers"). + VersionedParams(&opts, scheme.ParameterCodec). + Timeout(timeout). + Watch(ctx) +} + +// Create takes the representation of a router and creates it. Returns the server's representation of the router, and an error, if there is any. +func (c *routers) Create(ctx context.Context, router *v2beta2.Router, opts v1.CreateOptions) (result *v2beta2.Router, err error) { + result = &v2beta2.Router{} + err = c.client.Post(). + Resource("routers"). + VersionedParams(&opts, scheme.ParameterCodec). + Body(router). + Do(ctx). + Into(result) + return +} + +// Update takes the representation of a router and updates it. Returns the server's representation of the router, and an error, if there is any. +func (c *routers) Update(ctx context.Context, router *v2beta2.Router, opts v1.UpdateOptions) (result *v2beta2.Router, err error) { + result = &v2beta2.Router{} + err = c.client.Put(). + Resource("routers"). + Name(router.Name). + VersionedParams(&opts, scheme.ParameterCodec). + Body(router). + Do(ctx). + Into(result) + return +} + +// UpdateStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). +func (c *routers) UpdateStatus(ctx context.Context, router *v2beta2.Router, opts v1.UpdateOptions) (result *v2beta2.Router, err error) { + result = &v2beta2.Router{} + err = c.client.Put(). + Resource("routers"). + Name(router.Name). + SubResource("status"). + VersionedParams(&opts, scheme.ParameterCodec). + Body(router). + Do(ctx). + Into(result) + return +} + +// Delete takes name of the router and deletes it. Returns an error if one occurs. +func (c *routers) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { + return c.client.Delete(). + Resource("routers"). + Name(name). + Body(&opts). + Do(ctx). + Error() +} + +// DeleteCollection deletes a collection of objects. +func (c *routers) 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(). + Resource("routers"). + VersionedParams(&listOpts, scheme.ParameterCodec). + Timeout(timeout). + Body(&opts). + Do(ctx). + Error() +} + +// Patch applies the patch and returns the patched router. +func (c *routers) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v2beta2.Router, err error) { + result = &v2beta2.Router{} + err = c.client.Patch(pt). + Resource("routers"). + Name(name). + SubResource(subresources...). + VersionedParams(&opts, scheme.ParameterCodec). + Body(data). + Do(ctx). + Into(result) + return +} diff --git a/pkg/client/clientset/versioned/typed/notification/v2beta2/silence.go b/pkg/client/clientset/versioned/typed/notification/v2beta2/silence.go new file mode 100644 index 000000000..dc332469c --- /dev/null +++ b/pkg/client/clientset/versioned/typed/notification/v2beta2/silence.go @@ -0,0 +1,184 @@ +/* +Copyright 2020 The KubeSphere Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package v2beta2 + +import ( + "context" + "time" + + 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" + v2beta2 "kubesphere.io/api/notification/v2beta2" + scheme "kubesphere.io/kubesphere/pkg/client/clientset/versioned/scheme" +) + +// SilencesGetter has a method to return a SilenceInterface. +// A group's client should implement this interface. +type SilencesGetter interface { + Silences() SilenceInterface +} + +// SilenceInterface has methods to work with Silence resources. +type SilenceInterface interface { + Create(ctx context.Context, silence *v2beta2.Silence, opts v1.CreateOptions) (*v2beta2.Silence, error) + Update(ctx context.Context, silence *v2beta2.Silence, opts v1.UpdateOptions) (*v2beta2.Silence, error) + UpdateStatus(ctx context.Context, silence *v2beta2.Silence, opts v1.UpdateOptions) (*v2beta2.Silence, 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) (*v2beta2.Silence, error) + List(ctx context.Context, opts v1.ListOptions) (*v2beta2.SilenceList, 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 *v2beta2.Silence, err error) + SilenceExpansion +} + +// silences implements SilenceInterface +type silences struct { + client rest.Interface +} + +// newSilences returns a Silences +func newSilences(c *NotificationV2beta2Client) *silences { + return &silences{ + client: c.RESTClient(), + } +} + +// Get takes name of the silence, and returns the corresponding silence object, and an error if there is any. +func (c *silences) Get(ctx context.Context, name string, options v1.GetOptions) (result *v2beta2.Silence, err error) { + result = &v2beta2.Silence{} + err = c.client.Get(). + Resource("silences"). + Name(name). + VersionedParams(&options, scheme.ParameterCodec). + Do(ctx). + Into(result) + return +} + +// List takes label and field selectors, and returns the list of Silences that match those selectors. +func (c *silences) List(ctx context.Context, opts v1.ListOptions) (result *v2beta2.SilenceList, err error) { + var timeout time.Duration + if opts.TimeoutSeconds != nil { + timeout = time.Duration(*opts.TimeoutSeconds) * time.Second + } + result = &v2beta2.SilenceList{} + err = c.client.Get(). + Resource("silences"). + VersionedParams(&opts, scheme.ParameterCodec). + Timeout(timeout). + Do(ctx). + Into(result) + return +} + +// Watch returns a watch.Interface that watches the requested silences. +func (c *silences) 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(). + Resource("silences"). + VersionedParams(&opts, scheme.ParameterCodec). + Timeout(timeout). + Watch(ctx) +} + +// Create takes the representation of a silence and creates it. Returns the server's representation of the silence, and an error, if there is any. +func (c *silences) Create(ctx context.Context, silence *v2beta2.Silence, opts v1.CreateOptions) (result *v2beta2.Silence, err error) { + result = &v2beta2.Silence{} + err = c.client.Post(). + Resource("silences"). + VersionedParams(&opts, scheme.ParameterCodec). + Body(silence). + Do(ctx). + Into(result) + return +} + +// Update takes the representation of a silence and updates it. Returns the server's representation of the silence, and an error, if there is any. +func (c *silences) Update(ctx context.Context, silence *v2beta2.Silence, opts v1.UpdateOptions) (result *v2beta2.Silence, err error) { + result = &v2beta2.Silence{} + err = c.client.Put(). + Resource("silences"). + Name(silence.Name). + VersionedParams(&opts, scheme.ParameterCodec). + Body(silence). + Do(ctx). + Into(result) + return +} + +// UpdateStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). +func (c *silences) UpdateStatus(ctx context.Context, silence *v2beta2.Silence, opts v1.UpdateOptions) (result *v2beta2.Silence, err error) { + result = &v2beta2.Silence{} + err = c.client.Put(). + Resource("silences"). + Name(silence.Name). + SubResource("status"). + VersionedParams(&opts, scheme.ParameterCodec). + Body(silence). + Do(ctx). + Into(result) + return +} + +// Delete takes name of the silence and deletes it. Returns an error if one occurs. +func (c *silences) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { + return c.client.Delete(). + Resource("silences"). + Name(name). + Body(&opts). + Do(ctx). + Error() +} + +// DeleteCollection deletes a collection of objects. +func (c *silences) 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(). + Resource("silences"). + VersionedParams(&listOpts, scheme.ParameterCodec). + Timeout(timeout). + Body(&opts). + Do(ctx). + Error() +} + +// Patch applies the patch and returns the patched silence. +func (c *silences) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v2beta2.Silence, err error) { + result = &v2beta2.Silence{} + err = c.client.Patch(pt). + Resource("silences"). + Name(name). + SubResource(subresources...). + VersionedParams(&opts, scheme.ParameterCodec). + Body(data). + Do(ctx). + Into(result) + return +} diff --git a/pkg/client/clientset/versioned/typed/types/v1beta2/doc.go b/pkg/client/clientset/versioned/typed/types/v1beta2/doc.go new file mode 100644 index 000000000..1a24b5167 --- /dev/null +++ b/pkg/client/clientset/versioned/typed/types/v1beta2/doc.go @@ -0,0 +1,20 @@ +/* +Copyright 2020 The KubeSphere Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +// This package has the automatically generated typed clients. +package v1beta2 diff --git a/pkg/client/clientset/versioned/typed/types/v1beta2/fake/doc.go b/pkg/client/clientset/versioned/typed/types/v1beta2/fake/doc.go new file mode 100644 index 000000000..7e36dbca8 --- /dev/null +++ b/pkg/client/clientset/versioned/typed/types/v1beta2/fake/doc.go @@ -0,0 +1,20 @@ +/* +Copyright 2020 The KubeSphere Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +// Package fake has the automatically generated clients. +package fake diff --git a/pkg/client/clientset/versioned/typed/types/v1beta2/fake/fake_types_client.go b/pkg/client/clientset/versioned/typed/types/v1beta2/fake/fake_types_client.go new file mode 100644 index 000000000..800facdc2 --- /dev/null +++ b/pkg/client/clientset/versioned/typed/types/v1beta2/fake/fake_types_client.go @@ -0,0 +1,35 @@ +/* +Copyright 2020 The KubeSphere Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + rest "k8s.io/client-go/rest" + testing "k8s.io/client-go/testing" +) + +type FakeTypesV1beta2 struct { + *testing.Fake +} + +// RESTClient returns a RESTClient that is used to communicate +// with API server by this client implementation. +func (c *FakeTypesV1beta2) RESTClient() rest.Interface { + var ret *rest.RESTClient + return ret +} diff --git a/pkg/client/clientset/versioned/typed/types/v1beta2/generated_expansion.go b/pkg/client/clientset/versioned/typed/types/v1beta2/generated_expansion.go new file mode 100644 index 000000000..924a63f0b --- /dev/null +++ b/pkg/client/clientset/versioned/typed/types/v1beta2/generated_expansion.go @@ -0,0 +1,19 @@ +/* +Copyright 2020 The KubeSphere Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package v1beta2 diff --git a/pkg/client/clientset/versioned/typed/types/v1beta2/types_client.go b/pkg/client/clientset/versioned/typed/types/v1beta2/types_client.go new file mode 100644 index 000000000..4040608b5 --- /dev/null +++ b/pkg/client/clientset/versioned/typed/types/v1beta2/types_client.go @@ -0,0 +1,84 @@ +/* +Copyright 2020 The KubeSphere Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package v1beta2 + +import ( + rest "k8s.io/client-go/rest" + v1beta2 "kubesphere.io/api/types/v1beta2" + "kubesphere.io/kubesphere/pkg/client/clientset/versioned/scheme" +) + +type TypesV1beta2Interface interface { + RESTClient() rest.Interface +} + +// TypesV1beta2Client is used to interact with features provided by the types.kubefed.io group. +type TypesV1beta2Client struct { + restClient rest.Interface +} + +// NewForConfig creates a new TypesV1beta2Client for the given config. +func NewForConfig(c *rest.Config) (*TypesV1beta2Client, error) { + config := *c + if err := setConfigDefaults(&config); err != nil { + return nil, err + } + client, err := rest.RESTClientFor(&config) + if err != nil { + return nil, err + } + return &TypesV1beta2Client{client}, nil +} + +// NewForConfigOrDie creates a new TypesV1beta2Client for the given config and +// panics if there is an error in the config. +func NewForConfigOrDie(c *rest.Config) *TypesV1beta2Client { + client, err := NewForConfig(c) + if err != nil { + panic(err) + } + return client +} + +// New creates a new TypesV1beta2Client for the given RESTClient. +func New(c rest.Interface) *TypesV1beta2Client { + return &TypesV1beta2Client{c} +} + +func setConfigDefaults(config *rest.Config) error { + gv := v1beta2.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 *TypesV1beta2Client) RESTClient() rest.Interface { + if c == nil { + return nil + } + return c.restClient +} diff --git a/pkg/client/informers/externalversions/generic.go b/pkg/client/informers/externalversions/generic.go index b478120fa..4e607c635 100644 --- a/pkg/client/informers/externalversions/generic.go +++ b/pkg/client/informers/externalversions/generic.go @@ -31,6 +31,7 @@ import ( v1alpha2 "kubesphere.io/api/iam/v1alpha2" networkv1alpha1 "kubesphere.io/api/network/v1alpha1" v2beta1 "kubesphere.io/api/notification/v2beta1" + v2beta2 "kubesphere.io/api/notification/v2beta2" quotav1alpha2 "kubesphere.io/api/quota/v1alpha2" servicemeshv1alpha2 "kubesphere.io/api/servicemesh/v1alpha2" storagev1alpha1 "kubesphere.io/api/storage/v1alpha1" @@ -139,6 +140,16 @@ func (f *sharedInformerFactory) ForResource(resource schema.GroupVersionResource case v2beta1.SchemeGroupVersion.WithResource("receivers"): return &genericInformer{resource: resource.GroupResource(), informer: f.Notification().V2beta1().Receivers().Informer()}, nil + // Group=notification.kubesphere.io, Version=v2beta2 + case v2beta2.SchemeGroupVersion.WithResource("configs"): + return &genericInformer{resource: resource.GroupResource(), informer: f.Notification().V2beta2().Configs().Informer()}, nil + case v2beta2.SchemeGroupVersion.WithResource("receivers"): + return &genericInformer{resource: resource.GroupResource(), informer: f.Notification().V2beta2().Receivers().Informer()}, nil + case v2beta2.SchemeGroupVersion.WithResource("routers"): + return &genericInformer{resource: resource.GroupResource(), informer: f.Notification().V2beta2().Routers().Informer()}, nil + case v2beta2.SchemeGroupVersion.WithResource("silences"): + return &genericInformer{resource: resource.GroupResource(), informer: f.Notification().V2beta2().Silences().Informer()}, nil + // Group=quota.kubesphere.io, Version=v1alpha2 case quotav1alpha2.SchemeGroupVersion.WithResource("resourcequotas"): return &genericInformer{resource: resource.GroupResource(), informer: f.Quota().V1alpha2().ResourceQuotas().Informer()}, nil diff --git a/pkg/client/informers/externalversions/notification/interface.go b/pkg/client/informers/externalversions/notification/interface.go index 58de480dc..fee765c86 100644 --- a/pkg/client/informers/externalversions/notification/interface.go +++ b/pkg/client/informers/externalversions/notification/interface.go @@ -21,12 +21,15 @@ package notification import ( internalinterfaces "kubesphere.io/kubesphere/pkg/client/informers/externalversions/internalinterfaces" v2beta1 "kubesphere.io/kubesphere/pkg/client/informers/externalversions/notification/v2beta1" + v2beta2 "kubesphere.io/kubesphere/pkg/client/informers/externalversions/notification/v2beta2" ) // Interface provides access to each of this group's versions. type Interface interface { // V2beta1 provides access to shared informers for resources in V2beta1. V2beta1() v2beta1.Interface + // V2beta2 provides access to shared informers for resources in V2beta2. + V2beta2() v2beta2.Interface } type group struct { @@ -44,3 +47,8 @@ func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakList func (g *group) V2beta1() v2beta1.Interface { return v2beta1.New(g.factory, g.namespace, g.tweakListOptions) } + +// V2beta2 returns a new v2beta2.Interface. +func (g *group) V2beta2() v2beta2.Interface { + return v2beta2.New(g.factory, g.namespace, g.tweakListOptions) +} diff --git a/pkg/client/informers/externalversions/notification/v2beta2/config.go b/pkg/client/informers/externalversions/notification/v2beta2/config.go new file mode 100644 index 000000000..b7c521144 --- /dev/null +++ b/pkg/client/informers/externalversions/notification/v2beta2/config.go @@ -0,0 +1,89 @@ +/* +Copyright 2020 The KubeSphere Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by informer-gen. DO NOT EDIT. + +package v2beta2 + +import ( + "context" + time "time" + + 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" + notificationv2beta2 "kubesphere.io/api/notification/v2beta2" + versioned "kubesphere.io/kubesphere/pkg/client/clientset/versioned" + internalinterfaces "kubesphere.io/kubesphere/pkg/client/informers/externalversions/internalinterfaces" + v2beta2 "kubesphere.io/kubesphere/pkg/client/listers/notification/v2beta2" +) + +// ConfigInformer provides access to a shared informer and lister for +// Configs. +type ConfigInformer interface { + Informer() cache.SharedIndexInformer + Lister() v2beta2.ConfigLister +} + +type configInformer struct { + factory internalinterfaces.SharedInformerFactory + tweakListOptions internalinterfaces.TweakListOptionsFunc +} + +// NewConfigInformer constructs a new informer for Config 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 NewConfigInformer(client versioned.Interface, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer { + return NewFilteredConfigInformer(client, resyncPeriod, indexers, nil) +} + +// NewFilteredConfigInformer constructs a new informer for Config 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 NewFilteredConfigInformer(client versioned.Interface, 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.NotificationV2beta2().Configs().List(context.TODO(), options) + }, + WatchFunc: func(options v1.ListOptions) (watch.Interface, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.NotificationV2beta2().Configs().Watch(context.TODO(), options) + }, + }, + ¬ificationv2beta2.Config{}, + resyncPeriod, + indexers, + ) +} + +func (f *configInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer { + return NewFilteredConfigInformer(client, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions) +} + +func (f *configInformer) Informer() cache.SharedIndexInformer { + return f.factory.InformerFor(¬ificationv2beta2.Config{}, f.defaultInformer) +} + +func (f *configInformer) Lister() v2beta2.ConfigLister { + return v2beta2.NewConfigLister(f.Informer().GetIndexer()) +} diff --git a/pkg/client/informers/externalversions/notification/v2beta2/interface.go b/pkg/client/informers/externalversions/notification/v2beta2/interface.go new file mode 100644 index 000000000..052adede6 --- /dev/null +++ b/pkg/client/informers/externalversions/notification/v2beta2/interface.go @@ -0,0 +1,66 @@ +/* +Copyright 2020 The KubeSphere Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by informer-gen. DO NOT EDIT. + +package v2beta2 + +import ( + internalinterfaces "kubesphere.io/kubesphere/pkg/client/informers/externalversions/internalinterfaces" +) + +// Interface provides access to all the informers in this group version. +type Interface interface { + // Configs returns a ConfigInformer. + Configs() ConfigInformer + // Receivers returns a ReceiverInformer. + Receivers() ReceiverInformer + // Routers returns a RouterInformer. + Routers() RouterInformer + // Silences returns a SilenceInformer. + Silences() SilenceInformer +} + +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} +} + +// Configs returns a ConfigInformer. +func (v *version) Configs() ConfigInformer { + return &configInformer{factory: v.factory, tweakListOptions: v.tweakListOptions} +} + +// Receivers returns a ReceiverInformer. +func (v *version) Receivers() ReceiverInformer { + return &receiverInformer{factory: v.factory, tweakListOptions: v.tweakListOptions} +} + +// Routers returns a RouterInformer. +func (v *version) Routers() RouterInformer { + return &routerInformer{factory: v.factory, tweakListOptions: v.tweakListOptions} +} + +// Silences returns a SilenceInformer. +func (v *version) Silences() SilenceInformer { + return &silenceInformer{factory: v.factory, tweakListOptions: v.tweakListOptions} +} diff --git a/pkg/client/informers/externalversions/notification/v2beta2/receiver.go b/pkg/client/informers/externalversions/notification/v2beta2/receiver.go new file mode 100644 index 000000000..942acc75a --- /dev/null +++ b/pkg/client/informers/externalversions/notification/v2beta2/receiver.go @@ -0,0 +1,89 @@ +/* +Copyright 2020 The KubeSphere Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by informer-gen. DO NOT EDIT. + +package v2beta2 + +import ( + "context" + time "time" + + 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" + notificationv2beta2 "kubesphere.io/api/notification/v2beta2" + versioned "kubesphere.io/kubesphere/pkg/client/clientset/versioned" + internalinterfaces "kubesphere.io/kubesphere/pkg/client/informers/externalversions/internalinterfaces" + v2beta2 "kubesphere.io/kubesphere/pkg/client/listers/notification/v2beta2" +) + +// ReceiverInformer provides access to a shared informer and lister for +// Receivers. +type ReceiverInformer interface { + Informer() cache.SharedIndexInformer + Lister() v2beta2.ReceiverLister +} + +type receiverInformer struct { + factory internalinterfaces.SharedInformerFactory + tweakListOptions internalinterfaces.TweakListOptionsFunc +} + +// NewReceiverInformer constructs a new informer for Receiver 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 NewReceiverInformer(client versioned.Interface, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer { + return NewFilteredReceiverInformer(client, resyncPeriod, indexers, nil) +} + +// NewFilteredReceiverInformer constructs a new informer for Receiver 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 NewFilteredReceiverInformer(client versioned.Interface, 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.NotificationV2beta2().Receivers().List(context.TODO(), options) + }, + WatchFunc: func(options v1.ListOptions) (watch.Interface, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.NotificationV2beta2().Receivers().Watch(context.TODO(), options) + }, + }, + ¬ificationv2beta2.Receiver{}, + resyncPeriod, + indexers, + ) +} + +func (f *receiverInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer { + return NewFilteredReceiverInformer(client, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions) +} + +func (f *receiverInformer) Informer() cache.SharedIndexInformer { + return f.factory.InformerFor(¬ificationv2beta2.Receiver{}, f.defaultInformer) +} + +func (f *receiverInformer) Lister() v2beta2.ReceiverLister { + return v2beta2.NewReceiverLister(f.Informer().GetIndexer()) +} diff --git a/pkg/client/informers/externalversions/notification/v2beta2/router.go b/pkg/client/informers/externalversions/notification/v2beta2/router.go new file mode 100644 index 000000000..a6f36e316 --- /dev/null +++ b/pkg/client/informers/externalversions/notification/v2beta2/router.go @@ -0,0 +1,89 @@ +/* +Copyright 2020 The KubeSphere Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by informer-gen. DO NOT EDIT. + +package v2beta2 + +import ( + "context" + time "time" + + 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" + notificationv2beta2 "kubesphere.io/api/notification/v2beta2" + versioned "kubesphere.io/kubesphere/pkg/client/clientset/versioned" + internalinterfaces "kubesphere.io/kubesphere/pkg/client/informers/externalversions/internalinterfaces" + v2beta2 "kubesphere.io/kubesphere/pkg/client/listers/notification/v2beta2" +) + +// RouterInformer provides access to a shared informer and lister for +// Routers. +type RouterInformer interface { + Informer() cache.SharedIndexInformer + Lister() v2beta2.RouterLister +} + +type routerInformer struct { + factory internalinterfaces.SharedInformerFactory + tweakListOptions internalinterfaces.TweakListOptionsFunc +} + +// NewRouterInformer constructs a new informer for Router 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 NewRouterInformer(client versioned.Interface, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer { + return NewFilteredRouterInformer(client, resyncPeriod, indexers, nil) +} + +// NewFilteredRouterInformer constructs a new informer for Router 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 NewFilteredRouterInformer(client versioned.Interface, 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.NotificationV2beta2().Routers().List(context.TODO(), options) + }, + WatchFunc: func(options v1.ListOptions) (watch.Interface, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.NotificationV2beta2().Routers().Watch(context.TODO(), options) + }, + }, + ¬ificationv2beta2.Router{}, + resyncPeriod, + indexers, + ) +} + +func (f *routerInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer { + return NewFilteredRouterInformer(client, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions) +} + +func (f *routerInformer) Informer() cache.SharedIndexInformer { + return f.factory.InformerFor(¬ificationv2beta2.Router{}, f.defaultInformer) +} + +func (f *routerInformer) Lister() v2beta2.RouterLister { + return v2beta2.NewRouterLister(f.Informer().GetIndexer()) +} diff --git a/pkg/client/informers/externalversions/notification/v2beta2/silence.go b/pkg/client/informers/externalversions/notification/v2beta2/silence.go new file mode 100644 index 000000000..93b1b51fe --- /dev/null +++ b/pkg/client/informers/externalversions/notification/v2beta2/silence.go @@ -0,0 +1,89 @@ +/* +Copyright 2020 The KubeSphere Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by informer-gen. DO NOT EDIT. + +package v2beta2 + +import ( + "context" + time "time" + + 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" + notificationv2beta2 "kubesphere.io/api/notification/v2beta2" + versioned "kubesphere.io/kubesphere/pkg/client/clientset/versioned" + internalinterfaces "kubesphere.io/kubesphere/pkg/client/informers/externalversions/internalinterfaces" + v2beta2 "kubesphere.io/kubesphere/pkg/client/listers/notification/v2beta2" +) + +// SilenceInformer provides access to a shared informer and lister for +// Silences. +type SilenceInformer interface { + Informer() cache.SharedIndexInformer + Lister() v2beta2.SilenceLister +} + +type silenceInformer struct { + factory internalinterfaces.SharedInformerFactory + tweakListOptions internalinterfaces.TweakListOptionsFunc +} + +// NewSilenceInformer constructs a new informer for Silence 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 NewSilenceInformer(client versioned.Interface, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer { + return NewFilteredSilenceInformer(client, resyncPeriod, indexers, nil) +} + +// NewFilteredSilenceInformer constructs a new informer for Silence 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 NewFilteredSilenceInformer(client versioned.Interface, 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.NotificationV2beta2().Silences().List(context.TODO(), options) + }, + WatchFunc: func(options v1.ListOptions) (watch.Interface, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.NotificationV2beta2().Silences().Watch(context.TODO(), options) + }, + }, + ¬ificationv2beta2.Silence{}, + resyncPeriod, + indexers, + ) +} + +func (f *silenceInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer { + return NewFilteredSilenceInformer(client, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions) +} + +func (f *silenceInformer) Informer() cache.SharedIndexInformer { + return f.factory.InformerFor(¬ificationv2beta2.Silence{}, f.defaultInformer) +} + +func (f *silenceInformer) Lister() v2beta2.SilenceLister { + return v2beta2.NewSilenceLister(f.Informer().GetIndexer()) +} diff --git a/pkg/client/listers/notification/v2beta2/config.go b/pkg/client/listers/notification/v2beta2/config.go new file mode 100644 index 000000000..6dd5efd1c --- /dev/null +++ b/pkg/client/listers/notification/v2beta2/config.go @@ -0,0 +1,68 @@ +/* +Copyright 2020 The KubeSphere Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by lister-gen. DO NOT EDIT. + +package v2beta2 + +import ( + "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/labels" + "k8s.io/client-go/tools/cache" + v2beta2 "kubesphere.io/api/notification/v2beta2" +) + +// ConfigLister helps list Configs. +// All objects returned here must be treated as read-only. +type ConfigLister interface { + // List lists all Configs in the indexer. + // Objects returned here must be treated as read-only. + List(selector labels.Selector) (ret []*v2beta2.Config, err error) + // Get retrieves the Config from the index for a given name. + // Objects returned here must be treated as read-only. + Get(name string) (*v2beta2.Config, error) + ConfigListerExpansion +} + +// configLister implements the ConfigLister interface. +type configLister struct { + indexer cache.Indexer +} + +// NewConfigLister returns a new ConfigLister. +func NewConfigLister(indexer cache.Indexer) ConfigLister { + return &configLister{indexer: indexer} +} + +// List lists all Configs in the indexer. +func (s *configLister) List(selector labels.Selector) (ret []*v2beta2.Config, err error) { + err = cache.ListAll(s.indexer, selector, func(m interface{}) { + ret = append(ret, m.(*v2beta2.Config)) + }) + return ret, err +} + +// Get retrieves the Config from the index for a given name. +func (s *configLister) Get(name string) (*v2beta2.Config, error) { + obj, exists, err := s.indexer.GetByKey(name) + if err != nil { + return nil, err + } + if !exists { + return nil, errors.NewNotFound(v2beta2.Resource("config"), name) + } + return obj.(*v2beta2.Config), nil +} diff --git a/pkg/client/listers/notification/v2beta2/expansion_generated.go b/pkg/client/listers/notification/v2beta2/expansion_generated.go new file mode 100644 index 000000000..63d59d52d --- /dev/null +++ b/pkg/client/listers/notification/v2beta2/expansion_generated.go @@ -0,0 +1,35 @@ +/* +Copyright 2020 The KubeSphere Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by lister-gen. DO NOT EDIT. + +package v2beta2 + +// ConfigListerExpansion allows custom methods to be added to +// ConfigLister. +type ConfigListerExpansion interface{} + +// ReceiverListerExpansion allows custom methods to be added to +// ReceiverLister. +type ReceiverListerExpansion interface{} + +// RouterListerExpansion allows custom methods to be added to +// RouterLister. +type RouterListerExpansion interface{} + +// SilenceListerExpansion allows custom methods to be added to +// SilenceLister. +type SilenceListerExpansion interface{} diff --git a/pkg/client/listers/notification/v2beta2/receiver.go b/pkg/client/listers/notification/v2beta2/receiver.go new file mode 100644 index 000000000..22846d551 --- /dev/null +++ b/pkg/client/listers/notification/v2beta2/receiver.go @@ -0,0 +1,68 @@ +/* +Copyright 2020 The KubeSphere Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by lister-gen. DO NOT EDIT. + +package v2beta2 + +import ( + "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/labels" + "k8s.io/client-go/tools/cache" + v2beta2 "kubesphere.io/api/notification/v2beta2" +) + +// ReceiverLister helps list Receivers. +// All objects returned here must be treated as read-only. +type ReceiverLister interface { + // List lists all Receivers in the indexer. + // Objects returned here must be treated as read-only. + List(selector labels.Selector) (ret []*v2beta2.Receiver, err error) + // Get retrieves the Receiver from the index for a given name. + // Objects returned here must be treated as read-only. + Get(name string) (*v2beta2.Receiver, error) + ReceiverListerExpansion +} + +// receiverLister implements the ReceiverLister interface. +type receiverLister struct { + indexer cache.Indexer +} + +// NewReceiverLister returns a new ReceiverLister. +func NewReceiverLister(indexer cache.Indexer) ReceiverLister { + return &receiverLister{indexer: indexer} +} + +// List lists all Receivers in the indexer. +func (s *receiverLister) List(selector labels.Selector) (ret []*v2beta2.Receiver, err error) { + err = cache.ListAll(s.indexer, selector, func(m interface{}) { + ret = append(ret, m.(*v2beta2.Receiver)) + }) + return ret, err +} + +// Get retrieves the Receiver from the index for a given name. +func (s *receiverLister) Get(name string) (*v2beta2.Receiver, error) { + obj, exists, err := s.indexer.GetByKey(name) + if err != nil { + return nil, err + } + if !exists { + return nil, errors.NewNotFound(v2beta2.Resource("receiver"), name) + } + return obj.(*v2beta2.Receiver), nil +} diff --git a/pkg/client/listers/notification/v2beta2/router.go b/pkg/client/listers/notification/v2beta2/router.go new file mode 100644 index 000000000..793dbda51 --- /dev/null +++ b/pkg/client/listers/notification/v2beta2/router.go @@ -0,0 +1,68 @@ +/* +Copyright 2020 The KubeSphere Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by lister-gen. DO NOT EDIT. + +package v2beta2 + +import ( + "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/labels" + "k8s.io/client-go/tools/cache" + v2beta2 "kubesphere.io/api/notification/v2beta2" +) + +// RouterLister helps list Routers. +// All objects returned here must be treated as read-only. +type RouterLister interface { + // List lists all Routers in the indexer. + // Objects returned here must be treated as read-only. + List(selector labels.Selector) (ret []*v2beta2.Router, err error) + // Get retrieves the Router from the index for a given name. + // Objects returned here must be treated as read-only. + Get(name string) (*v2beta2.Router, error) + RouterListerExpansion +} + +// routerLister implements the RouterLister interface. +type routerLister struct { + indexer cache.Indexer +} + +// NewRouterLister returns a new RouterLister. +func NewRouterLister(indexer cache.Indexer) RouterLister { + return &routerLister{indexer: indexer} +} + +// List lists all Routers in the indexer. +func (s *routerLister) List(selector labels.Selector) (ret []*v2beta2.Router, err error) { + err = cache.ListAll(s.indexer, selector, func(m interface{}) { + ret = append(ret, m.(*v2beta2.Router)) + }) + return ret, err +} + +// Get retrieves the Router from the index for a given name. +func (s *routerLister) Get(name string) (*v2beta2.Router, error) { + obj, exists, err := s.indexer.GetByKey(name) + if err != nil { + return nil, err + } + if !exists { + return nil, errors.NewNotFound(v2beta2.Resource("router"), name) + } + return obj.(*v2beta2.Router), nil +} diff --git a/pkg/client/listers/notification/v2beta2/silence.go b/pkg/client/listers/notification/v2beta2/silence.go new file mode 100644 index 000000000..788207d27 --- /dev/null +++ b/pkg/client/listers/notification/v2beta2/silence.go @@ -0,0 +1,68 @@ +/* +Copyright 2020 The KubeSphere Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by lister-gen. DO NOT EDIT. + +package v2beta2 + +import ( + "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/labels" + "k8s.io/client-go/tools/cache" + v2beta2 "kubesphere.io/api/notification/v2beta2" +) + +// SilenceLister helps list Silences. +// All objects returned here must be treated as read-only. +type SilenceLister interface { + // List lists all Silences in the indexer. + // Objects returned here must be treated as read-only. + List(selector labels.Selector) (ret []*v2beta2.Silence, err error) + // Get retrieves the Silence from the index for a given name. + // Objects returned here must be treated as read-only. + Get(name string) (*v2beta2.Silence, error) + SilenceListerExpansion +} + +// silenceLister implements the SilenceLister interface. +type silenceLister struct { + indexer cache.Indexer +} + +// NewSilenceLister returns a new SilenceLister. +func NewSilenceLister(indexer cache.Indexer) SilenceLister { + return &silenceLister{indexer: indexer} +} + +// List lists all Silences in the indexer. +func (s *silenceLister) List(selector labels.Selector) (ret []*v2beta2.Silence, err error) { + err = cache.ListAll(s.indexer, selector, func(m interface{}) { + ret = append(ret, m.(*v2beta2.Silence)) + }) + return ret, err +} + +// Get retrieves the Silence from the index for a given name. +func (s *silenceLister) Get(name string) (*v2beta2.Silence, error) { + obj, exists, err := s.indexer.GetByKey(name) + if err != nil { + return nil, err + } + if !exists { + return nil, errors.NewNotFound(v2beta2.Resource("silence"), name) + } + return obj.(*v2beta2.Silence), nil +} diff --git a/pkg/controller/notification/notification_controller.go b/pkg/controller/notification/notification_controller.go index 71916c25e..2587362a0 100644 --- a/pkg/controller/notification/notification_controller.go +++ b/pkg/controller/notification/notification_controller.go @@ -36,14 +36,14 @@ import ( "k8s.io/client-go/tools/record" "k8s.io/client-go/util/workqueue" "k8s.io/klog" + "kubesphere.io/api/cluster/v1alpha1" + "kubesphere.io/api/notification/v2beta2" + "kubesphere.io/api/types/v1beta1" + "kubesphere.io/api/types/v1beta2" "sigs.k8s.io/controller-runtime/pkg/cache" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" - "kubesphere.io/api/cluster/v1alpha1" - "kubesphere.io/api/notification/v2beta1" - "kubesphere.io/api/types/v1beta1" - "kubesphere.io/kubesphere/pkg/constants" ) @@ -100,8 +100,10 @@ func (c *Controller) setEventHandlers() error { if c.reconciledObjs != nil && len(c.reconciledObjs) > 0 { c.reconciledObjs = c.reconciledObjs[:0] } - c.reconciledObjs = append(c.reconciledObjs, &v2beta1.Config{}) - c.reconciledObjs = append(c.reconciledObjs, &v2beta1.Receiver{}) + c.reconciledObjs = append(c.reconciledObjs, &v2beta2.Config{}) + c.reconciledObjs = append(c.reconciledObjs, &v2beta2.Receiver{}) + c.reconciledObjs = append(c.reconciledObjs, &v2beta2.Router{}) + c.reconciledObjs = append(c.reconciledObjs, &v2beta2.Silence{}) c.reconciledObjs = append(c.reconciledObjs, &corev1.Secret{}) if c.informerSynced != nil && len(c.informerSynced) > 0 { @@ -280,10 +282,14 @@ func (c *Controller) multiClusterSync(ctx context.Context, obj client.Object) er } switch obj := obj.(type) { - case *v2beta1.Config: + case *v2beta2.Config: return c.syncFederatedConfig(obj) - case *v2beta1.Receiver: + case *v2beta2.Receiver: return c.syncFederatedReceiver(obj) + case *v2beta2.Router: + return c.syncFederatedRouter(obj) + case *v2beta2.Silence: + return c.syncFederatedSilence(obj) case *corev1.Secret: return c.syncFederatedSecret(obj) default: @@ -292,28 +298,28 @@ func (c *Controller) multiClusterSync(ctx context.Context, obj client.Object) er } } -func (c *Controller) syncFederatedConfig(obj *v2beta1.Config) error { +func (c *Controller) syncFederatedConfig(obj *v2beta2.Config) error { - fedObj := &v1beta1.FederatedNotificationConfig{} + fedObj := &v1beta2.FederatedNotificationConfig{} err := c.Get(context.Background(), client.ObjectKey{Name: obj.Name}, fedObj) if err != nil { if errors.IsNotFound(err) { - fedObj = &v1beta1.FederatedNotificationConfig{ + fedObj = &v1beta2.FederatedNotificationConfig{ TypeMeta: metav1.TypeMeta{ - Kind: v1beta1.FederatedNotificationConfigKind, - APIVersion: v1beta1.SchemeGroupVersion.String(), + Kind: v1beta2.FederatedNotificationConfigKind, + APIVersion: v1beta2.SchemeGroupVersion.String(), }, ObjectMeta: metav1.ObjectMeta{ Name: obj.Name, }, - Spec: v1beta1.FederatedNotificationConfigSpec{ - Template: v1beta1.NotificationConfigTemplate{ + Spec: v1beta2.FederatedNotificationConfigSpec{ + Template: v1beta2.NotificationConfigTemplate{ ObjectMeta: metav1.ObjectMeta{ Labels: obj.Labels, }, Spec: obj.Spec, }, - Placement: v1beta1.GenericPlacementFields{ + Placement: v1beta2.GenericPlacementFields{ ClusterSelector: &metav1.LabelSelector{}, }, }, @@ -350,28 +356,28 @@ func (c *Controller) syncFederatedConfig(obj *v2beta1.Config) error { return nil } -func (c *Controller) syncFederatedReceiver(obj *v2beta1.Receiver) error { +func (c *Controller) syncFederatedReceiver(obj *v2beta2.Receiver) error { - fedObj := &v1beta1.FederatedNotificationReceiver{} + fedObj := &v1beta2.FederatedNotificationReceiver{} err := c.Get(context.Background(), client.ObjectKey{Name: obj.Name}, fedObj) if err != nil { if errors.IsNotFound(err) { - fedObj = &v1beta1.FederatedNotificationReceiver{ + fedObj = &v1beta2.FederatedNotificationReceiver{ TypeMeta: metav1.TypeMeta{ - Kind: v1beta1.FederatedNotificationReceiverKind, - APIVersion: v1beta1.SchemeGroupVersion.String(), + Kind: v1beta2.FederatedNotificationReceiverKind, + APIVersion: v1beta2.SchemeGroupVersion.String(), }, ObjectMeta: metav1.ObjectMeta{ Name: obj.Name, }, - Spec: v1beta1.FederatedNotificationReceiverSpec{ - Template: v1beta1.NotificationReceiverTemplate{ + Spec: v1beta2.FederatedNotificationReceiverSpec{ + Template: v1beta2.NotificationReceiverTemplate{ ObjectMeta: metav1.ObjectMeta{ Labels: obj.Labels, }, Spec: obj.Spec, }, - Placement: v1beta1.GenericPlacementFields{ + Placement: v1beta2.GenericPlacementFields{ ClusterSelector: &metav1.LabelSelector{}, }, }, @@ -408,6 +414,122 @@ func (c *Controller) syncFederatedReceiver(obj *v2beta1.Receiver) error { return nil } +func (c *Controller) syncFederatedRouter(obj *v2beta2.Router) error { + + fedObj := &v1beta2.FederatedNotificationRouter{} + err := c.Get(context.Background(), client.ObjectKey{Name: obj.Name}, fedObj) + if err != nil { + if errors.IsNotFound(err) { + fedObj = &v1beta2.FederatedNotificationRouter{ + TypeMeta: metav1.TypeMeta{ + Kind: v1beta2.FederatedNotificationReceiverKind, + APIVersion: v1beta2.SchemeGroupVersion.String(), + }, + ObjectMeta: metav1.ObjectMeta{ + Name: obj.Name, + }, + Spec: v1beta2.FederatedNotificationRouterSpec{ + Template: v1beta2.NotificationRouterTemplate{ + ObjectMeta: metav1.ObjectMeta{ + Labels: obj.Labels, + }, + Spec: obj.Spec, + }, + Placement: v1beta2.GenericPlacementFields{ + ClusterSelector: &metav1.LabelSelector{}, + }, + }, + } + + err = controllerutil.SetControllerReference(obj, fedObj, scheme.Scheme) + if err != nil { + klog.Errorf("FederatedNotificationRouter '%s' SetControllerReference failed, %s", obj.Name, err) + return err + } + + if err = c.Create(context.Background(), fedObj); err != nil { + klog.Errorf("create FederatedNotificationRouter '%s' failed, %s", obj.Name, err) + return err + } + + return nil + } + klog.Errorf("get FederatedNotificationRouter '%s' failed, %s", obj.Name, err) + return err + } + + if !reflect.DeepEqual(fedObj.Spec.Template.Labels, obj.Labels) || !reflect.DeepEqual(fedObj.Spec.Template.Spec, obj.Spec) { + + fedObj.Spec.Template.Spec = obj.Spec + fedObj.Spec.Template.Labels = obj.Labels + + if err := c.Update(context.Background(), fedObj); err != nil { + klog.Errorf("update FederatedNotificationRouter '%s' failed, %s", obj.Name, err) + return err + } + } + + return nil +} + +func (c *Controller) syncFederatedSilence(obj *v2beta2.Silence) error { + + fedObj := &v1beta2.FederatedNotificationSilence{} + err := c.Get(context.Background(), client.ObjectKey{Name: obj.Name}, fedObj) + if err != nil { + if errors.IsNotFound(err) { + fedObj = &v1beta2.FederatedNotificationSilence{ + TypeMeta: metav1.TypeMeta{ + Kind: v1beta2.FederatedNotificationReceiverKind, + APIVersion: v1beta2.SchemeGroupVersion.String(), + }, + ObjectMeta: metav1.ObjectMeta{ + Name: obj.Name, + }, + Spec: v1beta2.FederatedNotificationSilenceSpec{ + Template: v1beta2.NotificationSilenceTemplate{ + ObjectMeta: metav1.ObjectMeta{ + Labels: obj.Labels, + }, + Spec: obj.Spec, + }, + Placement: v1beta2.GenericPlacementFields{ + ClusterSelector: &metav1.LabelSelector{}, + }, + }, + } + + err = controllerutil.SetControllerReference(obj, fedObj, scheme.Scheme) + if err != nil { + klog.Errorf("FederatedNotificationSilence '%s' SetControllerReference failed, %s", obj.Name, err) + return err + } + + if err = c.Create(context.Background(), fedObj); err != nil { + klog.Errorf("create FederatedNotificationSilence '%s' failed, %s", obj.Name, err) + return err + } + + return nil + } + klog.Errorf("get FederatedNotificationSilence '%s' failed, %s", obj.Name, err) + return err + } + + if !reflect.DeepEqual(fedObj.Spec.Template.Labels, obj.Labels) || !reflect.DeepEqual(fedObj.Spec.Template.Spec, obj.Spec) { + + fedObj.Spec.Template.Spec = obj.Spec + fedObj.Spec.Template.Labels = obj.Labels + + if err := c.Update(context.Background(), fedObj); err != nil { + klog.Errorf("update FederatedNotificationSilence '%s' failed, %s", obj.Name, err) + return err + } + } + + return nil +} + func (c *Controller) syncFederatedSecret(obj *corev1.Secret) error { fedObj := &v1beta1.FederatedSecret{} diff --git a/pkg/controller/notification/notification_controller_test.go b/pkg/controller/notification/notification_controller_test.go index b5bd22cfb..23c78893f 100644 --- a/pkg/controller/notification/notification_controller_test.go +++ b/pkg/controller/notification/notification_controller_test.go @@ -26,20 +26,19 @@ import ( corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime/schema" + k8sinformers "k8s.io/client-go/informers" "k8s.io/client-go/kubernetes" fakek8s "k8s.io/client-go/kubernetes/fake" + "k8s.io/client-go/kubernetes/scheme" + "kubesphere.io/api/cluster/v1alpha1" + "kubesphere.io/api/notification/v2beta2" + "kubesphere.io/api/types/v1beta1" + "kubesphere.io/api/types/v1beta2" "sigs.k8s.io/controller-runtime/pkg/cache" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/client/fake" "sigs.k8s.io/controller-runtime/pkg/envtest/printer" - "kubesphere.io/api/cluster/v1alpha1" - "kubesphere.io/api/notification/v2beta1" - "kubesphere.io/api/types/v1beta1" - - k8sinformers "k8s.io/client-go/informers" - "k8s.io/client-go/kubernetes/scheme" - "kubesphere.io/kubesphere/pkg/apis" "kubesphere.io/kubesphere/pkg/constants" ) @@ -52,12 +51,13 @@ func TestSource(t *testing.T) { var ( _ = Describe("Secret", func() { - v2beta1.AddToScheme(scheme.Scheme) - apis.AddToScheme(scheme.Scheme) + _ = v2beta2.AddToScheme(scheme.Scheme) + _ = apis.AddToScheme(scheme.Scheme) + _ = v1beta2.AddToScheme(scheme.Scheme) secret := &corev1.Secret{ ObjectMeta: metav1.ObjectMeta{ - Name: "foo", + Name: "secret-foo", Namespace: constants.NotificationSecretNamespace, Labels: map[string]string{ constants.NotificationManagedLabel: "true", @@ -65,24 +65,39 @@ var ( }, } - config := &v2beta1.Config{ + config := &v2beta2.Config{ ObjectMeta: metav1.ObjectMeta{ - Name: "foo", + Name: "config-foo", Labels: map[string]string{ "type": "global", }, }, } - receiver := &v2beta1.Receiver{ + receiver := &v2beta2.Receiver{ ObjectMeta: metav1.ObjectMeta{ - Name: "foo", + Name: "receiver-foo", Labels: map[string]string{ "type": "default", }, }, } + router := &v2beta2.Router{ + ObjectMeta: metav1.ObjectMeta{ + Name: "router-foo", + }, + } + + silence := &v2beta2.Silence{ + ObjectMeta: metav1.ObjectMeta{ + Name: "silence-foo", + Labels: map[string]string{ + "type": "global", + }, + }, + } + host := &v1alpha1.Cluster{ ObjectMeta: metav1.ObjectMeta{ Name: "host", @@ -144,7 +159,7 @@ var ( Expect(cl.Create(context.Background(), config)).Should(Succeed()) Expect(r.reconcile(config)).Should(Succeed()) - fedConfig := &v1beta1.FederatedNotificationConfig{} + fedConfig := &v1beta2.FederatedNotificationConfig{} By("Expecting to create federated object successfully") err = ksCache.Get(context.Background(), client.ObjectKey{Name: config.Name}, fedConfig) Expect(err).Should(Succeed()) @@ -166,7 +181,7 @@ var ( Expect(cl.Create(context.Background(), receiver)).Should(Succeed()) Expect(r.reconcile(receiver)).Should(Succeed()) - fedReceiver := &v1beta1.FederatedNotificationReceiver{} + fedReceiver := &v1beta2.FederatedNotificationReceiver{} By("Expecting to create federated object successfully") err = ksCache.Get(context.Background(), client.ObjectKey{Name: receiver.Name}, fedReceiver) Expect(err).Should(Succeed()) @@ -185,6 +200,52 @@ var ( Expect(err).Should(Succeed()) Expect(fedReceiver.Spec.Template.Labels["foo"]).Should(Equal("bar")) + // Create a router + Expect(cl.Create(context.Background(), router)).Should(Succeed()) + Expect(r.reconcile(router)).Should(Succeed()) + + fedRouter := &v1beta2.FederatedNotificationRouter{} + By("Expecting to create federated object successfully") + err = ksCache.Get(context.Background(), client.ObjectKey{Name: router.Name}, fedRouter) + Expect(err).Should(Succeed()) + Expect(fedRouter.Name).Should(Equal(router.Name)) + + // Update a receiver + err = ksCache.Get(context.Background(), client.ObjectKey{Name: router.Name}, router) + Expect(err).Should(Succeed()) + router.Labels = map[string]string{"foo": "bar"} + Expect(cl.Update(context.Background(), router)).Should(Succeed()) + Expect(r.reconcile(router)).Should(Succeed()) + + By("Expecting to update federated object successfully") + + err = ksCache.Get(context.Background(), client.ObjectKey{Name: router.Name}, fedRouter) + Expect(err).Should(Succeed()) + Expect(fedRouter.Spec.Template.Labels["foo"]).Should(Equal("bar")) + + // Create a receiver + Expect(cl.Create(context.Background(), silence)).Should(Succeed()) + Expect(r.reconcile(silence)).Should(Succeed()) + + fedSilence := &v1beta2.FederatedNotificationSilence{} + By("Expecting to create federated object successfully") + err = ksCache.Get(context.Background(), client.ObjectKey{Name: silence.Name}, fedSilence) + Expect(err).Should(Succeed()) + Expect(fedSilence.Name).Should(Equal(silence.Name)) + + // Update a receiver + err = ksCache.Get(context.Background(), client.ObjectKey{Name: silence.Name}, silence) + Expect(err).Should(Succeed()) + silence.Labels = map[string]string{"foo": "bar"} + Expect(cl.Update(context.Background(), silence)).Should(Succeed()) + Expect(r.reconcile(silence)).Should(Succeed()) + + By("Expecting to update federated object successfully") + + err = ksCache.Get(context.Background(), client.ObjectKey{Name: silence.Name}, fedSilence) + Expect(err).Should(Succeed()) + Expect(fedSilence.Spec.Template.Labels["foo"]).Should(Equal("bar")) + // Add a cluster Expect(cl.Create(informerCacheCtx, host)).Should(Succeed()) Expect(r.reconcile(secret)).Should(Succeed()) @@ -220,24 +281,24 @@ type fakeCache struct { } // GetInformerForKind returns the informer for the GroupVersionKind -func (f *fakeCache) GetInformerForKind(ctx context.Context, gvk schema.GroupVersionKind) (cache.Informer, error) { +func (f *fakeCache) GetInformerForKind(_ context.Context, _ schema.GroupVersionKind) (cache.Informer, error) { return nil, nil } // GetInformer returns the informer for the obj -func (f *fakeCache) GetInformer(ctx context.Context, obj client.Object) (cache.Informer, error) { +func (f *fakeCache) GetInformer(_ context.Context, _ client.Object) (cache.Informer, error) { fakeInformerFactory := k8sinformers.NewSharedInformerFactory(f.K8sClient, defaultResync) return fakeInformerFactory.Core().V1().Namespaces().Informer(), nil } -func (f *fakeCache) IndexField(ctx context.Context, obj client.Object, field string, extractValue client.IndexerFunc) error { +func (f *fakeCache) IndexField(_ context.Context, _ client.Object, _ string, _ client.IndexerFunc) error { return nil } -func (f *fakeCache) Start(ctx context.Context) error { +func (f *fakeCache) Start(_ context.Context) error { return nil } -func (f *fakeCache) WaitForCacheSync(ctx context.Context) bool { +func (f *fakeCache) WaitForCacheSync(_ context.Context) bool { return true } diff --git a/pkg/kapis/notification/v2beta1/handler.go b/pkg/kapis/notification/v2beta1/handler.go index eeec19dad..4c43fb7d0 100644 --- a/pkg/kapis/notification/v2beta1/handler.go +++ b/pkg/kapis/notification/v2beta1/handler.go @@ -40,7 +40,7 @@ func newNotificationHandler( ksClient kubesphere.Interface) *handler { return &handler{ - operator: notification.NewOperator(informers, k8sClient, ksClient), + operator: notification.NewOperator(informers, k8sClient, ksClient, nil), } } @@ -51,12 +51,12 @@ func (h *handler) ListResource(req *restful.Request, resp *restful.Response) { subresource := req.QueryParameter("type") q := query.ParseQueryParameter(req) - if !h.operator.IsKnownResource(resource, subresource) { + if !h.operator.IsKnownResource(resource, notification.V2beta1, subresource) { api.HandleBadRequest(resp, req, servererr.New("unknown resource type %s/%s", resource, subresource)) return } - objs, err := h.operator.List(user, resource, subresource, q) + objs, err := h.operator.ListV2beta1(user, resource, subresource, q) handleResponse(req, resp, objs, err) } @@ -67,12 +67,12 @@ func (h *handler) GetResource(req *restful.Request, resp *restful.Response) { name := req.PathParameter("name") subresource := req.QueryParameter("type") - if !h.operator.IsKnownResource(resource, subresource) { + if !h.operator.IsKnownResource(resource, notification.V2beta1, subresource) { api.HandleBadRequest(resp, req, servererr.New("unknown resource type %s/%s", resource, subresource)) return } - obj, err := h.operator.Get(user, resource, name, subresource) + obj, err := h.operator.GetV2beta1(user, resource, name, subresource) handleResponse(req, resp, obj, err) } @@ -81,18 +81,18 @@ func (h *handler) CreateResource(req *restful.Request, resp *restful.Response) { user := req.PathParameter("user") resource := req.PathParameter("resources") - if !h.operator.IsKnownResource(resource, "") { + if !h.operator.IsKnownResource(resource, notification.V2beta1, "") { api.HandleBadRequest(resp, req, servererr.New("unknown resource type %s", resource)) return } - obj := h.operator.GetObject(resource) + obj := h.operator.GetObject(resource, notification.V2beta1) if err := req.ReadEntity(obj); err != nil { api.HandleBadRequest(resp, req, err) return } - created, err := h.operator.Create(user, resource, obj) + created, err := h.operator.CreateV2beta1(user, resource, obj) handleResponse(req, resp, created, err) } @@ -102,18 +102,18 @@ func (h *handler) UpdateResource(req *restful.Request, resp *restful.Response) { resource := req.PathParameter("resources") name := req.PathParameter("name") - if !h.operator.IsKnownResource(resource, "") { + if !h.operator.IsKnownResource(resource, notification.V2beta1, "") { api.HandleBadRequest(resp, req, servererr.New("unknown resource type %s", resource)) return } - obj := h.operator.GetObject(resource) + obj := h.operator.GetObject(resource, notification.V2beta1) if err := req.ReadEntity(obj); err != nil { api.HandleBadRequest(resp, req, err) return } - updated, err := h.operator.Update(user, resource, name, obj) + updated, err := h.operator.UpdateV2beta1(user, resource, name, obj) handleResponse(req, resp, updated, err) } @@ -123,12 +123,12 @@ func (h *handler) DeleteResource(req *restful.Request, resp *restful.Response) { resource := req.PathParameter("resources") name := req.PathParameter("name") - if !h.operator.IsKnownResource(resource, "") { + if !h.operator.IsKnownResource(resource, notification.V2beta1, "") { api.HandleBadRequest(resp, req, servererr.New("unknown resource type %s", resource)) return } - handleResponse(req, resp, servererr.None, h.operator.Delete(user, resource, name)) + handleResponse(req, resp, servererr.None, h.operator.DeleteV2beta1(user, resource, name)) } func handleResponse(req *restful.Request, resp *restful.Response, obj interface{}, err error) { diff --git a/pkg/kapis/notification/v2beta1/register.go b/pkg/kapis/notification/v2beta1/register.go index 3e8f9ad01..d1af290c9 100644 --- a/pkg/kapis/notification/v2beta1/register.go +++ b/pkg/kapis/notification/v2beta1/register.go @@ -53,6 +53,7 @@ func AddToContainer( // apis for global notification config, receiver, and secret ws.Route(ws.GET("/{resources}"). + Deprecate(). To(h.ListResource). Doc("list the notification configs or receivers"). Metadata(KeyOpenAPITags, []string{constants.NotificationTag}). @@ -67,6 +68,7 @@ func AddToContainer( Returns(http.StatusOK, api.StatusOK, api.ListResult{Items: []interface{}{}})) ws.Route(ws.GET("/{resources}/{name}"). + Deprecate(). To(h.GetResource). Doc("get the specified notification config or receiver"). Metadata(KeyOpenAPITags, []string{constants.NotificationTag}). @@ -76,6 +78,7 @@ func AddToContainer( Returns(http.StatusOK, api.StatusOK, nil)) ws.Route(ws.POST("/{resources}"). + Deprecate(). To(h.CreateResource). Doc("create a notification config or receiver"). Metadata(KeyOpenAPITags, []string{constants.NotificationTag}). @@ -83,6 +86,7 @@ func AddToContainer( Returns(http.StatusOK, api.StatusOK, nil)) ws.Route(ws.PUT("/{resources}/{name}"). + Deprecate(). To(h.UpdateResource). Doc("update the specified notification config or receiver"). Metadata(KeyOpenAPITags, []string{constants.NotificationTag}). @@ -91,6 +95,7 @@ func AddToContainer( Returns(http.StatusOK, api.StatusOK, nil)) ws.Route(ws.DELETE("/{resources}/{name}"). + Deprecate(). To(h.DeleteResource). Doc("delete the specified notification config or receiver"). Metadata(KeyOpenAPITags, []string{constants.NotificationTag}). @@ -100,6 +105,7 @@ func AddToContainer( // apis for tenant notification config and receiver ws.Route(ws.GET("/users/{user}/{resources}"). + Deprecate(). To(h.ListResource). Doc("list the notification configs or receivers"). Metadata(KeyOpenAPITags, []string{constants.NotificationTag}). @@ -115,6 +121,7 @@ func AddToContainer( Returns(http.StatusOK, api.StatusOK, api.ListResult{Items: []interface{}{}})) ws.Route(ws.GET("/users/{user}/{resources}/{name}"). + Deprecate(). To(h.GetResource). Doc("get the specified notification config or receiver"). Metadata(KeyOpenAPITags, []string{constants.NotificationTag}). @@ -125,6 +132,7 @@ func AddToContainer( Returns(http.StatusOK, api.StatusOK, nil)) ws.Route(ws.POST("/users/{user}/{resources}"). + Deprecate(). To(h.CreateResource). Doc("create the specified notification config or receiver"). Metadata(KeyOpenAPITags, []string{constants.NotificationTag}). @@ -133,6 +141,7 @@ func AddToContainer( Returns(http.StatusOK, api.StatusOK, nil)) ws.Route(ws.PUT("/users/{user}/{resources}/{name}"). + Deprecate(). To(h.UpdateResource). Doc("update the specified notification config or receiver"). Metadata(KeyOpenAPITags, []string{constants.NotificationTag}). @@ -142,6 +151,7 @@ func AddToContainer( Returns(http.StatusOK, api.StatusOK, nil)) ws.Route(ws.DELETE("/users/{user}/{resources}/{name}"). + Deprecate(). To(h.DeleteResource). Doc("delete the specified notification config or receiver"). Metadata(KeyOpenAPITags, []string{constants.NotificationTag}). diff --git a/pkg/kapis/notification/v2beta2/handler.go b/pkg/kapis/notification/v2beta2/handler.go index d091d2700..4e296f48c 100644 --- a/pkg/kapis/notification/v2beta2/handler.go +++ b/pkg/kapis/notification/v2beta2/handler.go @@ -12,117 +12,144 @@ // See the License for the specific language governing permissions and // limitations under the License. // + package v2beta2 import ( - "bytes" - "encoding/json" - "fmt" - "io" - "io/ioutil" - "net/http" - "github.com/emicklei/go-restful" - "kubesphere.io/api/notification/v2beta2" + "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/client-go/kubernetes" + "k8s.io/klog" - nm "kubesphere.io/kubesphere/pkg/simple/client/notification" -) - -const ( - VerificationAPIPath = "/api/v2/verify" + "kubesphere.io/kubesphere/pkg/api" + "kubesphere.io/kubesphere/pkg/apiserver/query" + kubesphere "kubesphere.io/kubesphere/pkg/client/clientset/versioned" + "kubesphere.io/kubesphere/pkg/informers" + nmoperator "kubesphere.io/kubesphere/pkg/models/notification" + servererr "kubesphere.io/kubesphere/pkg/server/errors" + "kubesphere.io/kubesphere/pkg/simple/client/notification" ) type handler struct { - option *nm.Options + operator nmoperator.Operator } -type Result struct { - Code int `json:"Status"` - Message string `json:"Message"` -} -type notification struct { - Config v2beta2.Config `json:"config"` - Receiver v2beta2.Receiver `json:"receiver"` -} +func newNotificationHandler( + informers informers.InformerFactory, + k8sClient kubernetes.Interface, + ksClient kubesphere.Interface, + options *notification.Options) *handler { -func newHandler(option *nm.Options) *handler { return &handler{ - option, + operator: nmoperator.NewOperator(informers, k8sClient, ksClient, options), } } -func (h handler) Verify(request *restful.Request, response *restful.Response) { - opt := h.option - if opt == nil || len(opt.Endpoint) == 0 { - response.WriteAsJson(Result{ - http.StatusBadRequest, - "Cannot find Notification Manager endpoint", - }) - } - host := opt.Endpoint - notification := notification{} - reqBody, err := ioutil.ReadAll(request.Request.Body) - if err != nil { - response.WriteHeaderAndEntity(http.StatusInternalServerError, err) +func (h *handler) ListResource(req *restful.Request, resp *restful.Response) { + + user := req.PathParameter("user") + resource := req.PathParameter("resources") + subresource := req.QueryParameter("type") + q := query.ParseQueryParameter(req) + + if !h.operator.IsKnownResource(resource, nmoperator.V2beta2, subresource) { + api.HandleBadRequest(resp, req, servererr.New("unknown resource type %s/%s", resource, subresource)) return } - err = json.Unmarshal(reqBody, ¬ification) - if err != nil { - response.WriteHeaderAndEntity(http.StatusInternalServerError, err) - return - } - - receiver := notification.Receiver - user := request.PathParameter("user") - - if receiver.Labels["type"] == "tenant" { - if user != receiver.Labels["user"] { - response.WriteAsJson(Result{ - http.StatusForbidden, - "Permission denied", - }) - return - } - } - if receiver.Labels["type"] == "global" { - if user != "" { - response.WriteAsJson(Result{ - http.StatusForbidden, - "Permission denied", - }) - return - } - } - - req, err := http.NewRequest("POST", fmt.Sprintf("%s%s", host, VerificationAPIPath), bytes.NewReader(reqBody)) - if err != nil { - response.WriteHeaderAndEntity(http.StatusInternalServerError, err) - return - } - req.Header = request.Request.Header - - client := &http.Client{} - resp, err := client.Do(req) - if err != nil { - response.WriteHeaderAndEntity(http.StatusInternalServerError, err) - return - } - defer resp.Body.Close() - - body, err := io.ReadAll(resp.Body) - if err != nil { - // return 500 - response.WriteHeaderAndEntity(http.StatusInternalServerError, err) - return - } - - var result Result - err = json.Unmarshal(body, &result) - if err != nil { - response.WriteHeaderAndEntity(http.StatusInternalServerError, err) - return - } - - response.WriteAsJson(result) + objs, err := h.operator.List(user, resource, subresource, q) + handleResponse(req, resp, objs, err) +} + +func (h *handler) GetResource(req *restful.Request, resp *restful.Response) { + + user := req.PathParameter("user") + resource := req.PathParameter("resources") + name := req.PathParameter("name") + subresource := req.QueryParameter("type") + + if !h.operator.IsKnownResource(resource, nmoperator.V2beta2, subresource) { + api.HandleBadRequest(resp, req, servererr.New("unknown resource type %s/%s", resource, subresource)) + return + } + + obj, err := h.operator.Get(user, resource, name, subresource) + handleResponse(req, resp, obj, err) +} + +func (h *handler) CreateResource(req *restful.Request, resp *restful.Response) { + + user := req.PathParameter("user") + resource := req.PathParameter("resources") + + if !h.operator.IsKnownResource(resource, nmoperator.V2beta2, "") { + api.HandleBadRequest(resp, req, servererr.New("unknown resource type %s", resource)) + return + } + + obj := h.operator.GetObject(resource, nmoperator.V2beta2) + if err := req.ReadEntity(obj); err != nil { + api.HandleBadRequest(resp, req, err) + return + } + + created, err := h.operator.Create(user, resource, obj) + handleResponse(req, resp, created, err) +} + +func (h *handler) UpdateResource(req *restful.Request, resp *restful.Response) { + + user := req.PathParameter("user") + resource := req.PathParameter("resources") + name := req.PathParameter("name") + + if !h.operator.IsKnownResource(resource, nmoperator.V2beta2, "") { + api.HandleBadRequest(resp, req, servererr.New("unknown resource type %s", resource)) + return + } + + obj := h.operator.GetObject(resource, nmoperator.V2beta2) + if err := req.ReadEntity(obj); err != nil { + api.HandleBadRequest(resp, req, err) + return + } + + updated, err := h.operator.Update(user, resource, name, obj) + handleResponse(req, resp, updated, err) +} + +func (h *handler) DeleteResource(req *restful.Request, resp *restful.Response) { + + user := req.PathParameter("user") + resource := req.PathParameter("resources") + name := req.PathParameter("name") + + if !h.operator.IsKnownResource(resource, nmoperator.V2beta2, "") { + api.HandleBadRequest(resp, req, servererr.New("unknown resource type %s", resource)) + return + } + + handleResponse(req, resp, servererr.None, h.operator.Delete(user, resource, name)) +} + +func (h *handler) Verify(req *restful.Request, resp *restful.Response) { + h.operator.Verify(req, resp) +} + +func handleResponse(req *restful.Request, resp *restful.Response, obj interface{}, err error) { + + if err != nil { + klog.Error(err) + if errors.IsNotFound(err) { + api.HandleNotFound(resp, req, err) + return + } else if errors.IsConflict(err) { + api.HandleConflict(resp, req, err) + return + } + api.HandleBadRequest(resp, req, err) + return + } + + _ = resp.WriteEntity(obj) } diff --git a/pkg/kapis/notification/v2beta2/register.go b/pkg/kapis/notification/v2beta2/register.go index 83174aeb9..99524842c 100644 --- a/pkg/kapis/notification/v2beta2/register.go +++ b/pkg/kapis/notification/v2beta2/register.go @@ -21,20 +21,38 @@ package v2beta2 import ( "net/http" - nm "kubesphere.io/kubesphere/pkg/simple/client/notification" - "github.com/emicklei/go-restful" + openapi "github.com/emicklei/go-restful-openapi" "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/client-go/kubernetes" "kubesphere.io/kubesphere/pkg/api" + "kubesphere.io/kubesphere/pkg/apiserver/query" "kubesphere.io/kubesphere/pkg/apiserver/runtime" + kubesphere "kubesphere.io/kubesphere/pkg/client/clientset/versioned" + "kubesphere.io/kubesphere/pkg/constants" + "kubesphere.io/kubesphere/pkg/informers" + "kubesphere.io/kubesphere/pkg/server/errors" + "kubesphere.io/kubesphere/pkg/simple/client/notification" ) -var GroupVersion = schema.GroupVersion{Group: "notification.kubesphere.io", Version: "v2beta2"} +const ( + GroupName = "notification.kubesphere.io" + KeyOpenAPITags = openapi.KeyOpenAPITags +) + +var GroupVersion = schema.GroupVersion{Group: GroupName, Version: "v2beta2"} + +func AddToContainer( + container *restful.Container, + informers informers.InformerFactory, + k8sClient kubernetes.Interface, + ksClient kubesphere.Interface, + options *notification.Options) error { -func AddToContainer(container *restful.Container, option *nm.Options) error { - h := newHandler(option) ws := runtime.NewWebService(GroupVersion) + h := newNotificationHandler(informers, k8sClient, ksClient, options) + ws.Route(ws.POST("/configs/notification/verification"). Reads(""). To(h.Verify). @@ -45,6 +63,106 @@ func AddToContainer(container *restful.Container, option *nm.Options) error { Param(ws.PathParameter("user", "user name")). Returns(http.StatusOK, api.StatusOK, http.Response{}.Body)). Doc("Provide validation for notification-manager information") + + // apis for global notification config, receiver, and secret + ws.Route(ws.GET("/{resources}"). + To(h.ListResource). + Doc("list the notification configs or receivers"). + Metadata(KeyOpenAPITags, []string{constants.NotificationTag}). + Param(ws.PathParameter("resources", "known values include configs, receivers, secrets, routers, silences")). + Param(ws.QueryParameter(query.ParameterName, "name used for filtering").Required(false)). + Param(ws.QueryParameter(query.ParameterLabelSelector, "label selector used for filtering").Required(false)). + Param(ws.QueryParameter("type", "config or receiver type, known values include dingtalk, email, feishu, slack, webhook, wechat").Required(false)). + Param(ws.QueryParameter(query.ParameterPage, "page").Required(false).DataFormat("page=%d").DefaultValue("page=1")). + Param(ws.QueryParameter(query.ParameterLimit, "limit").Required(false)). + Param(ws.QueryParameter(query.ParameterAscending, "sort parameters, e.g. ascending=false").Required(false).DefaultValue("ascending=false")). + Param(ws.QueryParameter(query.ParameterOrderBy, "sort parameters, e.g. orderBy=createTime")). + Returns(http.StatusOK, api.StatusOK, api.ListResult{Items: []interface{}{}})) + + ws.Route(ws.GET("/{resources}/{name}"). + To(h.GetResource). + Doc("get the specified notification config or receiver"). + Metadata(KeyOpenAPITags, []string{constants.NotificationTag}). + Param(ws.PathParameter("resources", "known values include configs, receivers, secrets, routers, silences")). + Param(ws.PathParameter(query.ParameterName, "the name of the resource")). + Param(ws.QueryParameter("type", "config or receiver type, known values include dingtalk, feishu, email, slack, webhook, wechat").Required(false)). + Returns(http.StatusOK, api.StatusOK, nil)) + + ws.Route(ws.POST("/{resources}"). + To(h.CreateResource). + Doc("create a notification config or receiver"). + Metadata(KeyOpenAPITags, []string{constants.NotificationTag}). + Param(ws.PathParameter("resources", "known values include configs, receivers, secrets, routers, silences")). + Returns(http.StatusOK, api.StatusOK, nil)) + + ws.Route(ws.PUT("/{resources}/{name}"). + To(h.UpdateResource). + Doc("update the specified notification config or receiver"). + Metadata(KeyOpenAPITags, []string{constants.NotificationTag}). + Param(ws.PathParameter("resources", "known values include configs, receivers, secrets, routers, silences")). + Param(ws.PathParameter(query.ParameterName, "the name of the resource")). + Returns(http.StatusOK, api.StatusOK, nil)) + + ws.Route(ws.DELETE("/{resources}/{name}"). + To(h.DeleteResource). + Doc("delete the specified notification config or receiver"). + Metadata(KeyOpenAPITags, []string{constants.NotificationTag}). + Param(ws.PathParameter("resources", "known values include configs, receivers, secrets, routers, silences")). + Param(ws.PathParameter(query.ParameterName, "the name of the resource")). + Returns(http.StatusOK, api.StatusOK, errors.None)) + + // apis for tenant notification config and receiver + ws.Route(ws.GET("/users/{user}/{resources}"). + To(h.ListResource). + Doc("list the notification configs or receivers"). + Metadata(KeyOpenAPITags, []string{constants.NotificationTag}). + Param(ws.PathParameter("user", "user name")). + Param(ws.PathParameter("resources", "known values include configs, receivers, secrets, silences")). + Param(ws.QueryParameter(query.ParameterName, "name used for filtering").Required(false)). + Param(ws.QueryParameter(query.ParameterLabelSelector, "label selector used for filtering").Required(false)). + Param(ws.QueryParameter("type", "config or receiver type, known values include dingtalk, email, feishu, slack, webhook, wechat").Required(false)). + Param(ws.QueryParameter(query.ParameterPage, "page").Required(false).DataFormat("page=%d").DefaultValue("page=1")). + Param(ws.QueryParameter(query.ParameterLimit, "limit").Required(false)). + Param(ws.QueryParameter(query.ParameterAscending, "sort parameters, e.g. ascending=false").Required(false).DefaultValue("ascending=false")). + Param(ws.QueryParameter(query.ParameterOrderBy, "sort parameters, e.g. orderBy=createTime")). + Returns(http.StatusOK, api.StatusOK, api.ListResult{Items: []interface{}{}})) + + ws.Route(ws.GET("/users/{user}/{resources}/{name}"). + To(h.GetResource). + Doc("get the specified notification config or receiver"). + Metadata(KeyOpenAPITags, []string{constants.NotificationTag}). + Param(ws.PathParameter("user", "user name")). + Param(ws.PathParameter("resources", "known values include configs, receivers, secrets, silences")). + Param(ws.PathParameter(query.ParameterName, "the name of the resource")). + Param(ws.QueryParameter("type", "config or receiver type, known values include dingtalk, email, feishu, slack, webhook, wechat").Required(false)). + Returns(http.StatusOK, api.StatusOK, nil)) + + ws.Route(ws.POST("/users/{user}/{resources}"). + To(h.CreateResource). + Doc("create the specified notification config or receiver"). + Metadata(KeyOpenAPITags, []string{constants.NotificationTag}). + Param(ws.PathParameter("user", "user name")). + Param(ws.PathParameter("resources", "known values include configs, receivers, secrets, silences")). + Returns(http.StatusOK, api.StatusOK, nil)) + + ws.Route(ws.PUT("/users/{user}/{resources}/{name}"). + To(h.UpdateResource). + Doc("update the specified notification config or receiver"). + Metadata(KeyOpenAPITags, []string{constants.NotificationTag}). + Param(ws.PathParameter("user", "user name")). + Param(ws.PathParameter("resources", "known values include configs, receivers, secrets, silences")). + Param(ws.PathParameter(query.ParameterName, "the name of the resource")). + Returns(http.StatusOK, api.StatusOK, nil)) + + ws.Route(ws.DELETE("/users/{user}/{resources}/{name}"). + To(h.DeleteResource). + Doc("delete the specified notification config or receiver"). + Metadata(KeyOpenAPITags, []string{constants.NotificationTag}). + Param(ws.PathParameter("user", "user name")). + Param(ws.PathParameter("resources", "known values include configs, receivers, secrets, silences")). + Param(ws.PathParameter(query.ParameterName, "the name of the resource")). + Returns(http.StatusOK, api.StatusOK, errors.None)) + container.Add(ws) return nil } diff --git a/pkg/models/notification/notification.go b/pkg/models/notification/notification.go index 4b3f89582..5683f21a0 100644 --- a/pkg/models/notification/notification.go +++ b/pkg/models/notification/notification.go @@ -12,13 +12,20 @@ // See the License for the specific language governing permissions and // limitations under the License. // + package notification import ( + "bytes" "context" + "encoding/json" "fmt" + "io" + "io/ioutil" + "net/http" "reflect" + "github.com/emicklei/go-restful" corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/api/meta" @@ -26,8 +33,8 @@ import ( "k8s.io/apimachinery/pkg/runtime" "k8s.io/client-go/kubernetes" "k8s.io/klog" - "kubesphere.io/api/notification/v2beta1" + "kubesphere.io/api/notification/v2beta2" "kubesphere.io/kubesphere/pkg/api" "kubesphere.io/kubesphere/pkg/apiserver/query" @@ -35,21 +42,34 @@ import ( "kubesphere.io/kubesphere/pkg/constants" "kubesphere.io/kubesphere/pkg/informers" "kubesphere.io/kubesphere/pkg/models/resources/v1alpha3/resource" + "kubesphere.io/kubesphere/pkg/simple/client/notification" ) const ( - Secret = "secrets" + Secret = "secrets" + VerificationAPIPath = "/api/v2/verify" + + V2beta1 = "v2beta1" + V2beta2 = "v2beta2" ) type Operator interface { + ListV2beta1(user, resource, subresource string, query *query.Query) (*api.ListResult, error) + GetV2beta1(user, resource, name, subresource string) (runtime.Object, error) + CreateV2beta1(user, resource string, obj runtime.Object) (runtime.Object, error) + DeleteV2beta1(user, resource, name string) error + UpdateV2beta1(user, resource, name string, obj runtime.Object) (runtime.Object, error) + List(user, resource, subresource string, query *query.Query) (*api.ListResult, error) Get(user, resource, name, subresource string) (runtime.Object, error) Create(user, resource string, obj runtime.Object) (runtime.Object, error) Delete(user, resource, name string) error Update(user, resource, name string, obj runtime.Object) (runtime.Object, error) - GetObject(resource string) runtime.Object - IsKnownResource(resource, subresource string) bool + Verify(request *restful.Request, response *restful.Response) + + GetObject(resource, version string) runtime.Object + IsKnownResource(resource, version, subresource string) bool } type operator struct { @@ -57,24 +77,52 @@ type operator struct { ksClient kubesphere.Interface informers informers.InformerFactory resourceGetter *resource.ResourceGetter + options *notification.Options +} + +type Data struct { + Config v2beta2.Config `json:"config"` + Receiver v2beta2.Receiver `json:"receiver"` +} + +type Result struct { + Code int `json:"Status"` + Message string `json:"Message"` } func NewOperator( informers informers.InformerFactory, k8sClient kubernetes.Interface, - ksClient kubesphere.Interface) Operator { + ksClient kubesphere.Interface, + options *notification.Options) Operator { return &operator{ informers: informers, k8sClient: k8sClient, ksClient: ksClient, resourceGetter: resource.NewResourceGetter(informers, nil), + options: options, } } +// ListV2beta1 list objects of version v2beta1. Only global objects will be returned if the user is nil. +// If the user is not nil, only tenant objects whose tenant label matches the user will be returned. +func (o *operator) ListV2beta1(user, resource, subresource string, q *query.Query) (*api.ListResult, error) { + return o.list(user, resource, V2beta1, subresource, q) +} + // List objects. Only global objects will be returned if the user is nil. // If the user is not nil, only tenant objects whose tenant label matches the user will be returned. func (o *operator) List(user, resource, subresource string, q *query.Query) (*api.ListResult, error) { + return o.list(user, resource, V2beta2, subresource, q) +} + +func (o *operator) list(user, resource, version, subresource string, q *query.Query) (*api.ListResult, error) { + + if user != "" && resource == v2beta2.ResourcesPluralRouter { + return nil, errors.NewForbidden(v2beta2.Resource(v2beta2.ResourcesPluralRouter), "", + fmt.Errorf("tenant can not list router")) + } if len(q.LabelSelector) > 0 { q.LabelSelector = q.LabelSelector + "," @@ -83,7 +131,7 @@ func (o *operator) List(user, resource, subresource string, q *query.Query) (*ap filter := "" // If user is nil, it will list all global object. if user == "" { - if isConfig(o.GetObject(resource)) { + if isConfig(o.GetObject(resource, version)) { filter = "type=default" } else { filter = "type=global" @@ -102,6 +150,7 @@ func (o *operator) List(user, resource, subresource string, q *query.Query) (*ap res, err := o.resourceGetter.List(resource, ns, q) if err != nil { + klog.Error(err) return nil, err } @@ -113,6 +162,9 @@ func (o *operator) List(user, resource, subresource string, q *query.Query) (*ap for _, item := range res.Items { obj := clean(item, resource, subresource) if obj != nil { + if version == V2beta1 { + obj = convert(obj) + } results.Items = append(results.Items, obj) } } @@ -121,9 +173,24 @@ func (o *operator) List(user, resource, subresource string, q *query.Query) (*ap return results, nil } +// GetV2beta1 get the specified object of version v2beta1, if you want to get a global object, the user must be nil. +// If you want to get a tenant object, the user must equal to the tenant specified in labels of the object. +func (o *operator) GetV2beta1(user, resource, name, subresource string) (runtime.Object, error) { + return o.get(user, resource, V2beta1, name, subresource) +} + // Get the specified object, if you want to get a global object, the user must be nil. // If you want to get a tenant object, the user must equal to the tenant specified in labels of the object. func (o *operator) Get(user, resource, name, subresource string) (runtime.Object, error) { + return o.get(user, resource, V2beta2, name, subresource) +} + +func (o *operator) get(user, resource, version, name, subresource string) (runtime.Object, error) { + + if user != "" && resource == v2beta2.ResourcesPluralRouter { + return nil, errors.NewForbidden(v2beta2.Resource(v2beta2.ResourcesPluralRouter), "", + fmt.Errorf("tenant can not get router")) + } ns := "" if resource == Secret { @@ -132,10 +199,12 @@ func (o *operator) Get(user, resource, name, subresource string) (runtime.Object obj, err := o.resourceGetter.Get(resource, ns, name) if err != nil { + klog.Error(err) return nil, err } if err := authorizer(user, obj); err != nil { + klog.Error(err) return nil, err } @@ -148,22 +217,53 @@ func (o *operator) Get(user, resource, name, subresource string) (runtime.Object return nil, errors.NewNotFound(v2beta1.Resource(obj.GetObjectKind().GroupVersionKind().GroupKind().Kind), name) } + if version == V2beta1 { + res = convert(res) + } + return res, nil } +// CreateV2beta1 an object of version v2beta1. A global object will be created if the user is nil. +// A tenant object will be created if the user is not nil. +func (o *operator) CreateV2beta1(user, resource string, obj runtime.Object) (runtime.Object, error) { + return o.create(user, resource, V2beta1, obj) +} + // Create an object. A global object will be created if the user is nil. // A tenant object will be created if the user is not nil. func (o *operator) Create(user, resource string, obj runtime.Object) (runtime.Object, error) { + return o.create(user, resource, V2beta2, obj) +} + +func (o *operator) create(user, resource, version string, obj runtime.Object) (runtime.Object, error) { if err := appendLabel(user, resource, obj); err != nil { return nil, err } + if user != "" && resource == v2beta2.ResourcesPluralRouter { + return nil, errors.NewForbidden(v2beta2.Resource(v2beta2.ResourcesPluralRouter), "", + fmt.Errorf("tenant can not create router")) + } + switch resource { - case v2beta1.ResourcesPluralConfig: - return o.ksClient.NotificationV2beta1().Configs().Create(context.Background(), obj.(*v2beta1.Config), v1.CreateOptions{}) - case v2beta1.ResourcesPluralReceiver: - return o.ksClient.NotificationV2beta1().Receivers().Create(context.Background(), obj.(*v2beta1.Receiver), v1.CreateOptions{}) + case v2beta2.ResourcesPluralConfig: + if version == V2beta1 { + return o.ksClient.NotificationV2beta1().Configs().Create(context.Background(), obj.(*v2beta1.Config), v1.CreateOptions{}) + } else { + return o.ksClient.NotificationV2beta2().Configs().Create(context.Background(), obj.(*v2beta2.Config), v1.CreateOptions{}) + } + case v2beta2.ResourcesPluralReceiver: + if version == V2beta1 { + return o.ksClient.NotificationV2beta1().Receivers().Create(context.Background(), obj.(*v2beta1.Receiver), v1.CreateOptions{}) + } else { + return o.ksClient.NotificationV2beta2().Receivers().Create(context.Background(), obj.(*v2beta2.Receiver), v1.CreateOptions{}) + } + case v2beta2.ResourcesPluralRouter: + return o.ksClient.NotificationV2beta2().Routers().Create(context.Background(), obj.(*v2beta2.Router), v1.CreateOptions{}) + case v2beta2.ResourcesPluralSilence: + return o.ksClient.NotificationV2beta2().Silences().Create(context.Background(), obj.(*v2beta2.Silence), v1.CreateOptions{}) case "secrets": return o.k8sClient.CoreV1().Secrets(constants.NotificationSecretNamespace).Create(context.Background(), obj.(*corev1.Secret), v1.CreateOptions{}) default: @@ -171,23 +271,44 @@ func (o *operator) Create(user, resource string, obj runtime.Object) (runtime.Ob } } +// DeleteV2beta1 an object of version v2beta1. A global object will be deleted if the user is nil. +// If the user is not nil, a tenant object whose tenant label matches the user will be deleted. +func (o *operator) DeleteV2beta1(user, resource, name string) error { + return o.delete(user, resource, name) +} + // Delete an object. A global object will be deleted if the user is nil. // If the user is not nil, a tenant object whose tenant label matches the user will be deleted. func (o *operator) Delete(user, resource, name string) error { + return o.delete(user, resource, name) +} + +func (o *operator) delete(user, resource, name string) error { + + if user != "" && resource == v2beta2.ResourcesPluralRouter { + return errors.NewForbidden(v2beta2.Resource(v2beta2.ResourcesPluralRouter), "", + fmt.Errorf("tenant can not delete router")) + } if obj, err := o.Get(user, resource, name, ""); err != nil { + klog.Error(err) return err } else { if err := authorizer(user, obj); err != nil { + klog.Error(err) return err } } switch resource { - case v2beta1.ResourcesPluralConfig: - return o.ksClient.NotificationV2beta1().Configs().Delete(context.Background(), name, v1.DeleteOptions{}) - case v2beta1.ResourcesPluralReceiver: - return o.ksClient.NotificationV2beta1().Receivers().Delete(context.Background(), name, v1.DeleteOptions{}) + case v2beta2.ResourcesPluralConfig: + return o.ksClient.NotificationV2beta2().Configs().Delete(context.Background(), name, v1.DeleteOptions{}) + case v2beta2.ResourcesPluralReceiver: + return o.ksClient.NotificationV2beta2().Receivers().Delete(context.Background(), name, v1.DeleteOptions{}) + case v2beta2.ResourcesPluralRouter: + return o.ksClient.NotificationV2beta2().Routers().Delete(context.Background(), name, v1.DeleteOptions{}) + case v2beta2.ResourcesPluralSilence: + return o.ksClient.NotificationV2beta2().Silences().Delete(context.Background(), name, v1.DeleteOptions{}) case "secrets": return o.k8sClient.CoreV1().Secrets(constants.NotificationSecretNamespace).Delete(context.Background(), name, v1.DeleteOptions{}) default: @@ -195,27 +316,56 @@ func (o *operator) Delete(user, resource, name string) error { } } +// UpdateV2beta1 an object of version v2beta1, only a global object will be updated if the user is nil. +// If the user is not nil, a tenant object whose tenant label matches the user will be updated. +func (o *operator) UpdateV2beta1(user, resource, name string, obj runtime.Object) (runtime.Object, error) { + return o.update(user, resource, V2beta1, name, obj) +} + // Update an object, only a global object will be updated if the user is nil. // If the user is not nil, a tenant object whose tenant label matches the user will be updated. func (o *operator) Update(user, resource, name string, obj runtime.Object) (runtime.Object, error) { + return o.update(user, resource, V2beta2, name, obj) +} + +func (o *operator) update(user, resource, version, name string, obj runtime.Object) (runtime.Object, error) { + + if user != "" && resource == v2beta2.ResourcesPluralRouter { + return nil, errors.NewForbidden(v2beta2.Resource(v2beta2.ResourcesPluralRouter), "", + fmt.Errorf("tenant can not update router")) + } if err := appendLabel(user, resource, obj); err != nil { return nil, err } if old, err := o.Get(user, resource, name, ""); err != nil { + klog.Error(err) return nil, err } else { if err := authorizer(user, old); err != nil { + klog.Error(err) return nil, err } } switch resource { - case v2beta1.ResourcesPluralConfig: - return o.ksClient.NotificationV2beta1().Configs().Update(context.Background(), obj.(*v2beta1.Config), v1.UpdateOptions{}) - case v2beta1.ResourcesPluralReceiver: - return o.ksClient.NotificationV2beta1().Receivers().Update(context.Background(), obj.(*v2beta1.Receiver), v1.UpdateOptions{}) + case v2beta2.ResourcesPluralConfig: + if version == V2beta1 { + return o.ksClient.NotificationV2beta1().Configs().Update(context.Background(), obj.(*v2beta1.Config), v1.UpdateOptions{}) + } else { + return o.ksClient.NotificationV2beta2().Configs().Update(context.Background(), obj.(*v2beta2.Config), v1.UpdateOptions{}) + } + case v2beta2.ResourcesPluralReceiver: + if version == V2beta1 { + return o.ksClient.NotificationV2beta1().Receivers().Update(context.Background(), obj.(*v2beta1.Receiver), v1.UpdateOptions{}) + } else { + return o.ksClient.NotificationV2beta2().Receivers().Update(context.Background(), obj.(*v2beta2.Receiver), v1.UpdateOptions{}) + } + case v2beta2.ResourcesPluralRouter: + return o.ksClient.NotificationV2beta2().Routers().Update(context.Background(), obj.(*v2beta2.Router), v1.UpdateOptions{}) + case v2beta2.ResourcesPluralSilence: + return o.ksClient.NotificationV2beta2().Silences().Update(context.Background(), obj.(*v2beta2.Silence), v1.UpdateOptions{}) case "secrets": return o.k8sClient.CoreV1().Secrets(constants.NotificationSecretNamespace).Update(context.Background(), obj.(*corev1.Secret), v1.UpdateOptions{}) default: @@ -223,13 +373,31 @@ func (o *operator) Update(user, resource, name string, obj runtime.Object) (runt } } -func (o *operator) GetObject(resource string) runtime.Object { +func (o *operator) GetObject(resource, version string) runtime.Object { switch resource { - case v2beta1.ResourcesPluralConfig: - return &v2beta1.Config{} - case v2beta1.ResourcesPluralReceiver: - return &v2beta1.Receiver{} + case v2beta2.ResourcesPluralConfig: + if version == V2beta1 { + return &v2beta1.Config{} + } else { + return &v2beta2.Config{} + } + case v2beta2.ResourcesPluralReceiver: + if version == V2beta1 { + return &v2beta1.Receiver{} + } else { + return &v2beta2.Receiver{} + } + case v2beta2.ResourcesPluralRouter: + if version == V2beta1 { + return nil + } + return &v2beta2.Router{} + case v2beta2.ResourcesPluralSilence: + if version == V2beta1 { + return nil + } + return &v2beta2.Silence{} case Secret: return &corev1.Secret{} default: @@ -237,36 +405,105 @@ func (o *operator) GetObject(resource string) runtime.Object { } } -func (o *operator) IsKnownResource(resource, subresource string) bool { +func (o *operator) IsKnownResource(resource, version, subresource string) bool { - if obj := o.GetObject(resource); obj == nil { + if obj := o.GetObject(resource, version); obj == nil { return false } + res := false // "" means get all types of the config or receiver. - if subresource != "dingtalk" && - subresource != "email" && - subresource != "slack" && - subresource != "webhook" && - subresource != "wechat" && - subresource != "" { - return false + if subresource == "dingtalk" || + subresource == "email" || + subresource == "slack" || + subresource == "webhook" || + subresource == "wechat" || + subresource == "" { + res = true } - return true + if version == V2beta2 && subresource == "feishu" { + res = true + } + + return res +} + +func (o *operator) Verify(request *restful.Request, response *restful.Response) { + if o.options == nil || len(o.options.Endpoint) == 0 { + _ = response.WriteAsJson(Result{ + http.StatusInternalServerError, + "Cannot find Notification Manager endpoint", + }) + return + } + + reqBody, err := ioutil.ReadAll(request.Request.Body) + if err != nil { + klog.Error(err) + _ = response.WriteHeaderAndEntity(http.StatusBadRequest, err) + return + } + + data := Data{} + err = json.Unmarshal(reqBody, &data) + if err != nil { + _ = response.WriteHeaderAndEntity(http.StatusBadRequest, err) + return + } + + receiver := data.Receiver + user := request.PathParameter("user") + + if err := authorizer(user, &receiver); err != nil { + klog.Error(err) + _ = response.WriteHeaderAndEntity(http.StatusBadRequest, err) + return + } + + req, err := http.NewRequest("POST", fmt.Sprintf("%s%s", o.options.Endpoint, VerificationAPIPath), bytes.NewReader(reqBody)) + if err != nil { + klog.Error(err) + _ = response.WriteHeaderAndEntity(http.StatusInternalServerError, err) + return + } + req.Header = request.Request.Header + + client := &http.Client{} + resp, err := client.Do(req) + if err != nil { + klog.Error(err) + _ = response.WriteHeaderAndEntity(http.StatusInternalServerError, err) + return + } + defer func() { + _ = resp.Body.Close() + }() + + body, err := io.ReadAll(resp.Body) + if err != nil { + klog.Error(err) + // return 500 + _ = response.WriteHeaderAndEntity(http.StatusInternalServerError, err) + return + } + + response.AddHeader(restful.HEADER_ContentType, restful.MIME_JSON) + response.WriteHeader(http.StatusOK) + _, _ = response.Write(body) } // Does the user has permission to access this object. func authorizer(user string, obj runtime.Object) error { // If the user is not nil, it must equal to the tenant specified in labels of the object. if user != "" && !isOwner(user, obj) { - return errors.NewForbidden(v2beta1.Resource(obj.GetObjectKind().GroupVersionKind().GroupKind().Kind), "", + return errors.NewForbidden(v2beta2.Resource(obj.GetObjectKind().GroupVersionKind().GroupKind().Kind), "", fmt.Errorf("user '%s' is not the owner of object", user)) } // If the user is nil, the object must be a global object. if user == "" && !isGlobal(obj) { - return errors.NewForbidden(v2beta1.Resource(obj.GetObjectKind().GroupVersionKind().GroupKind().Kind), "", + return errors.NewForbidden(v2beta2.Resource(obj.GetObjectKind().GroupVersionKind().GroupKind().Kind), "", fmt.Errorf("object is not a global object")) } @@ -282,12 +519,12 @@ func isOwner(user string, obj interface{}) bool { return false } - return accessor.GetLabels()["user"] == user + return accessor.GetLabels()["user"] == user && accessor.GetLabels()["type"] == "tenant" } func isConfig(obj runtime.Object) bool { switch obj.(type) { - case *v2beta1.Config: + case *v2beta1.Config, *v2beta2.Config: return true default: return false @@ -342,15 +579,17 @@ func appendLabel(user, resource string, obj runtime.Object) error { } func clean(obj interface{}, resource, subresource string) runtime.Object { - if resource == v2beta1.ResourcesPluralConfig { - config := obj.(*v2beta1.Config) + if resource == v2beta2.ResourcesPluralConfig { + config := obj.(*v2beta2.Config) newConfig := config.DeepCopy() - newConfig.Spec = v2beta1.ConfigSpec{} + newConfig.Spec = v2beta2.ConfigSpec{} switch subresource { case "dingtalk": newConfig.Spec.DingTalk = config.Spec.DingTalk case "email": newConfig.Spec.Email = config.Spec.Email + case "feishu": + newConfig.Spec.Feishu = config.Spec.Feishu case "slack": newConfig.Spec.Slack = config.Spec.Slack case "webhook": @@ -366,15 +605,17 @@ func clean(obj interface{}, resource, subresource string) runtime.Object { } return newConfig - } else { - receiver := obj.(*v2beta1.Receiver) + } else if resource == v2beta2.ResourcesPluralReceiver { + receiver := obj.(*v2beta2.Receiver) newReceiver := receiver.DeepCopy() - newReceiver.Spec = v2beta1.ReceiverSpec{} + newReceiver.Spec = v2beta2.ReceiverSpec{} switch subresource { case "dingtalk": newReceiver.Spec.DingTalk = receiver.Spec.DingTalk case "email": newReceiver.Spec.Email = receiver.Spec.Email + case "feishu": + newReceiver.Spec.Feishu = receiver.Spec.Feishu case "slack": newReceiver.Spec.Slack = receiver.Spec.Slack case "webhook": @@ -390,5 +631,22 @@ func clean(obj interface{}, resource, subresource string) runtime.Object { } return newReceiver + } else { + return obj.(runtime.Object) + } +} + +func convert(obj runtime.Object) runtime.Object { + switch obj := obj.(type) { + case *v2beta2.Config: + dst := &v2beta1.Config{} + _ = obj.ConvertTo(dst) + return dst + case *v2beta2.Receiver: + dst := &v2beta1.Receiver{} + _ = obj.ConvertTo(dst) + return dst + default: + return obj } } diff --git a/pkg/models/notification/notification_test.go b/pkg/models/notification/notification_test.go index f382dd017..a087c8735 100644 --- a/pkg/models/notification/notification_test.go +++ b/pkg/models/notification/notification_test.go @@ -217,5 +217,5 @@ func prepare() Operator { _ = fakeInformerFactory.KubernetesSharedInformerFactory().Core().V1().Secrets().Informer().GetIndexer().Add(secret) } - return NewOperator(fakeInformerFactory, k8sClient, ksClient) + return NewOperator(fakeInformerFactory, k8sClient, ksClient, nil) } diff --git a/pkg/models/resources/v1alpha3/notification/notification.go b/pkg/models/resources/v1alpha3/notification/notification.go index 480ed56ab..68d525411 100644 --- a/pkg/models/resources/v1alpha3/notification/notification.go +++ b/pkg/models/resources/v1alpha3/notification/notification.go @@ -37,11 +37,11 @@ func NewNotificationConfigGetter(informer ksinformers.SharedInformerFactory) v1a } func (g *configGetter) Get(_, name string) (runtime.Object, error) { - return g.ksInformer.Notification().V2beta1().Configs().Lister().Get(name) + return g.ksInformer.Notification().V2beta2().Configs().Lister().Get(name) } func (g *configGetter) List(_ string, query *query.Query) (*api.ListResult, error) { - objs, err := g.ksInformer.Notification().V2beta1().Configs().Lister().List(query.Selector()) + objs, err := g.ksInformer.Notification().V2beta2().Configs().Lister().List(query.Selector()) if err != nil { return nil, err } @@ -62,11 +62,61 @@ func NewNotificationReceiverGetter(informer ksinformers.SharedInformerFactory) v } func (g *receiverGetter) Get(_, name string) (runtime.Object, error) { - return g.ksInformer.Notification().V2beta1().Receivers().Lister().Get(name) + return g.ksInformer.Notification().V2beta2().Receivers().Lister().Get(name) } func (g *receiverGetter) List(_ string, query *query.Query) (*api.ListResult, error) { - objs, err := g.ksInformer.Notification().V2beta1().Receivers().Lister().List(query.Selector()) + objs, err := g.ksInformer.Notification().V2beta2().Receivers().Lister().List(query.Selector()) + if err != nil { + return nil, err + } + + var result []runtime.Object + for _, obj := range objs { + result = append(result, obj) + } + return v1alpha3.DefaultList(result, query, compare, filter), nil +} + +type routerGetter struct { + ksInformer ksinformers.SharedInformerFactory +} + +func NewNotificationRouterGetter(informer ksinformers.SharedInformerFactory) v1alpha3.Interface { + return &routerGetter{ksInformer: informer} +} + +func (g *routerGetter) Get(_, name string) (runtime.Object, error) { + return g.ksInformer.Notification().V2beta2().Routers().Lister().Get(name) +} + +func (g *routerGetter) List(_ string, query *query.Query) (*api.ListResult, error) { + objs, err := g.ksInformer.Notification().V2beta2().Routers().Lister().List(query.Selector()) + if err != nil { + return nil, err + } + + var result []runtime.Object + for _, obj := range objs { + result = append(result, obj) + } + return v1alpha3.DefaultList(result, query, compare, filter), nil +} + +type silenceGetter struct { + ksInformer ksinformers.SharedInformerFactory +} + +func NewNotificationSilenceGetter(informer ksinformers.SharedInformerFactory) v1alpha3.Interface { + return &silenceGetter{ksInformer: informer} +} + +func (g *silenceGetter) Get(_, name string) (runtime.Object, error) { + return g.ksInformer.Notification().V2beta2().Silences().Lister().Get(name) +} + +func (g *silenceGetter) List(_ string, query *query.Query) (*api.ListResult, error) { + objs, err := g.ksInformer.Notification().V2beta2().Silences().Lister().List(query.Selector()) if err != nil { return nil, err } diff --git a/pkg/models/resources/v1alpha3/notification/notification_test.go b/pkg/models/resources/v1alpha3/notification/notification_test.go index 9bcc2389e..ba50998d2 100644 --- a/pkg/models/resources/v1alpha3/notification/notification_test.go +++ b/pkg/models/resources/v1alpha3/notification/notification_test.go @@ -26,8 +26,7 @@ import ( "k8s.io/apimachinery/pkg/api/meta" "k8s.io/apimachinery/pkg/runtime" "k8s.io/client-go/tools/cache" - - "kubesphere.io/api/notification/v2beta1" + "kubesphere.io/api/notification/v2beta2" "kubesphere.io/kubesphere/pkg/api" "kubesphere.io/kubesphere/pkg/apiserver/query" @@ -50,11 +49,19 @@ func TestListObjects(t *testing.T) { }{ { "test name filter", - v2beta1.ResourcesPluralConfig, + v2beta2.ResourcesPluralConfig, }, { "test name filter", - v2beta1.ResourcesPluralReceiver, + v2beta2.ResourcesPluralReceiver, + }, + { + "test name filter", + v2beta2.ResourcesPluralRouter, + }, + { + "test name filter", + v2beta2.ResourcesPluralSilence, }, } @@ -99,14 +106,22 @@ func prepare(key string) (v1alpha3.Interface, []interface{}, error) { var indexer cache.Indexer var getter func(informer ksinformers.SharedInformerFactory) v1alpha3.Interface switch key { - case v2beta1.ResourcesPluralConfig: - indexer = informer.Notification().V2beta1().Configs().Informer().GetIndexer() + case v2beta2.ResourcesPluralConfig: + indexer = informer.Notification().V2beta2().Configs().Informer().GetIndexer() getter = NewNotificationConfigGetter - obj = &v2beta1.Config{} - case v2beta1.ResourcesPluralReceiver: - indexer = informer.Notification().V2beta1().Receivers().Informer().GetIndexer() + obj = &v2beta2.Config{} + case v2beta2.ResourcesPluralReceiver: + indexer = informer.Notification().V2beta2().Receivers().Informer().GetIndexer() getter = NewNotificationReceiverGetter - obj = &v2beta1.Receiver{} + obj = &v2beta2.Receiver{} + case v2beta2.ResourcesPluralRouter: + indexer = informer.Notification().V2beta2().Routers().Informer().GetIndexer() + getter = NewNotificationRouterGetter + obj = &v2beta2.Router{} + case v2beta2.ResourcesPluralSilence: + indexer = informer.Notification().V2beta2().Silences().Informer().GetIndexer() + getter = NewNotificationSilenceGetter + obj = &v2beta2.Silence{} default: return nil, nil, errors.New("unowned type %s", key) } diff --git a/pkg/models/resources/v1alpha3/resource/resource.go b/pkg/models/resources/v1alpha3/resource/resource.go index f6da869c0..d10b61d40 100644 --- a/pkg/models/resources/v1alpha3/resource/resource.go +++ b/pkg/models/resources/v1alpha3/resource/resource.go @@ -36,7 +36,7 @@ import ( devopsv1alpha3 "kubesphere.io/api/devops/v1alpha3" iamv1alpha2 "kubesphere.io/api/iam/v1alpha2" networkv1alpha1 "kubesphere.io/api/network/v1alpha1" - notificationv2beta1 "kubesphere.io/api/notification/v2beta1" + notificationv2beta2 "kubesphere.io/api/notification/v2beta2" tenantv1alpha1 "kubesphere.io/api/tenant/v1alpha1" tenantv1alpha2 "kubesphere.io/api/tenant/v1alpha2" typesv1beta1 "kubesphere.io/api/types/v1beta1" @@ -143,8 +143,10 @@ func NewResourceGetter(factory informers.InformerFactory, cache cache.Cache) *Re clusterResourceGetters[rbacv1.SchemeGroupVersion.WithResource(iamv1alpha2.ResourcesPluralClusterRole)] = clusterrole.New(factory.KubernetesSharedInformerFactory()) clusterResourceGetters[rbacv1.SchemeGroupVersion.WithResource(iamv1alpha2.ResourcesPluralClusterRoleBinding)] = clusterrolebinding.New(factory.KubernetesSharedInformerFactory()) clusterResourceGetters[clusterv1alpha1.SchemeGroupVersion.WithResource(clusterv1alpha1.ResourcesPluralCluster)] = cluster.New(factory.KubeSphereSharedInformerFactory()) - clusterResourceGetters[notificationv2beta1.SchemeGroupVersion.WithResource(notificationv2beta1.ResourcesPluralConfig)] = notification.NewNotificationConfigGetter(factory.KubeSphereSharedInformerFactory()) - clusterResourceGetters[notificationv2beta1.SchemeGroupVersion.WithResource(notificationv2beta1.ResourcesPluralReceiver)] = notification.NewNotificationReceiverGetter(factory.KubeSphereSharedInformerFactory()) + clusterResourceGetters[notificationv2beta2.SchemeGroupVersion.WithResource(notificationv2beta2.ResourcesPluralConfig)] = notification.NewNotificationConfigGetter(factory.KubeSphereSharedInformerFactory()) + clusterResourceGetters[notificationv2beta2.SchemeGroupVersion.WithResource(notificationv2beta2.ResourcesPluralReceiver)] = notification.NewNotificationReceiverGetter(factory.KubeSphereSharedInformerFactory()) + clusterResourceGetters[notificationv2beta2.SchemeGroupVersion.WithResource(notificationv2beta2.ResourcesPluralRouter)] = notification.NewNotificationRouterGetter(factory.KubeSphereSharedInformerFactory()) + clusterResourceGetters[notificationv2beta2.SchemeGroupVersion.WithResource(notificationv2beta2.ResourcesPluralSilence)] = notification.NewNotificationSilenceGetter(factory.KubeSphereSharedInformerFactory()) clusterResourceGetters[monitoringdashboardv1alpha2.GroupVersion.WithResource("clusterdashboards")] = clusterdashboard.New(cache) // federated resources diff --git a/staging/src/kubesphere.io/api/go.mod b/staging/src/kubesphere.io/api/go.mod index f9b263595..124742652 100644 --- a/staging/src/kubesphere.io/api/go.mod +++ b/staging/src/kubesphere.io/api/go.mod @@ -10,6 +10,7 @@ require ( github.com/go-openapi/spec v0.19.7 github.com/onsi/gomega v1.15.0 github.com/projectcalico/libcalico-go v1.7.2-0.20191014160346-2382c6cdd056 + github.com/robfig/cron/v3 v3.0.1 golang.org/x/net v0.0.0-20210525063256-abc453219eb5 istio.io/api v0.0.0-20201113182140-d4b7e3fc2b44 k8s.io/api v0.21.2 diff --git a/staging/src/kubesphere.io/api/go.sum b/staging/src/kubesphere.io/api/go.sum index 2335e5cb3..cc011887f 100644 --- a/staging/src/kubesphere.io/api/go.sum +++ b/staging/src/kubesphere.io/api/go.sum @@ -454,6 +454,8 @@ github.com/prometheus/procfs v0.6.0 h1:mxy4L2jP6qMonqmq+aTtOx1ifVWUgG/TAmntgbh3x github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= github.com/remyoudompheng/bigfft v0.0.0-20170806203942-52369c62f446/go.mod h1:uYEyJGbgTkfkS4+E/PavXkNJcbFIpEtjt2B0KDQ5+9M= +github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs= +github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro= github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= diff --git a/staging/src/kubesphere.io/api/notification/v2beta1/config_types.go b/staging/src/kubesphere.io/api/notification/v2beta1/config_types.go index de1d4dea5..57f25f463 100644 --- a/staging/src/kubesphere.io/api/notification/v2beta1/config_types.go +++ b/staging/src/kubesphere.io/api/notification/v2beta1/config_types.go @@ -138,7 +138,8 @@ type ConfigStatus struct { // +kubebuilder:subresource:status // +genclient // +genclient:nonNamespaced -// DingTalkConfig is the Schema for the dingtalkconfigs API + +// Config is the Schema for the configs API type Config struct { metav1.TypeMeta `json:",inline"` metav1.ObjectMeta `json:"metadata,omitempty"` @@ -159,3 +160,5 @@ type ConfigList struct { func init() { SchemeBuilder.Register(&Config{}, &ConfigList{}) } + +func (_ *Config) Hub() {} diff --git a/staging/src/kubesphere.io/api/notification/v2beta1/receiver_types.go b/staging/src/kubesphere.io/api/notification/v2beta1/receiver_types.go index 5d3921946..c6ff71982 100644 --- a/staging/src/kubesphere.io/api/notification/v2beta1/receiver_types.go +++ b/staging/src/kubesphere.io/api/notification/v2beta1/receiver_types.go @@ -195,3 +195,5 @@ type ReceiverList struct { func init() { SchemeBuilder.Register(&Receiver{}, &ReceiverList{}) } + +func (_ *Receiver) Hub() {} diff --git a/staging/src/kubesphere.io/api/notification/v2beta2/config_conversion.go b/staging/src/kubesphere.io/api/notification/v2beta2/config_conversion.go new file mode 100644 index 000000000..f44362e9b --- /dev/null +++ b/staging/src/kubesphere.io/api/notification/v2beta2/config_conversion.go @@ -0,0 +1,340 @@ +/* + + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v2beta2 + +import ( + "kubesphere.io/api/notification/v2beta1" + "sigs.k8s.io/controller-runtime/pkg/conversion" +) + +// ConvertTo converts this Config to the Hub version (v2beta1). +func (src *Config) ConvertTo(dstRaw conversion.Hub) error { + + dst := dstRaw.(*v2beta1.Config) + dst.ObjectMeta = src.ObjectMeta + + if err := src.convertDingTalkTo(dst); err != nil { + return err + } + + if err := src.convertEmailTo(dst); err != nil { + return err + } + + if err := src.convertSlackTo(dst); err != nil { + return err + } + + if err := src.convertWebhookTo(dst); err != nil { + return err + } + + if err := src.convertWechatTo(dst); err != nil { + return err + } + + return nil +} + +// ConvertFrom converts from the Hub version (v2beta1) to this version. +func (dst *Config) ConvertFrom(srcRaw conversion.Hub) error { + + src := srcRaw.(*v2beta1.Config) + dst.ObjectMeta = src.ObjectMeta + + if err := dst.convertDingTalkFrom(src); err != nil { + return err + } + + if err := dst.convertEmailFrom(src); err != nil { + return err + } + + if err := dst.convertSlackFrom(src); err != nil { + return err + } + + if err := dst.convertWebhookFrom(src); err != nil { + return err + } + + if err := dst.convertWechatFrom(src); err != nil { + return err + } + + return nil +} + +func (src *Config) convertDingTalkTo(dst *v2beta1.Config) error { + + if src.Spec.DingTalk == nil { + return nil + } + + dingtalk := src.Spec.DingTalk + dst.Spec.DingTalk = &v2beta1.DingTalkConfig{ + Labels: dingtalk.Labels, + } + + if dingtalk.Conversation != nil { + dst.Spec.DingTalk.Conversation = &v2beta1.DingTalkApplicationConfig{ + AppKey: credentialToSecretKeySelector(dingtalk.Conversation.AppKey), + AppSecret: credentialToSecretKeySelector(dingtalk.Conversation.AppSecret), + } + } + + return nil +} + +func (src *Config) convertEmailTo(dst *v2beta1.Config) error { + + if src.Spec.Email == nil { + return nil + } + + email := src.Spec.Email + dst.Spec.Email = &v2beta1.EmailConfig{ + Labels: email.Labels, + From: email.From, + SmartHost: v2beta1.HostPort{ + Host: email.SmartHost.Host, + Port: email.SmartHost.Port, + }, + Hello: email.Hello, + AuthUsername: email.AuthUsername, + AuthPassword: credentialToSecretKeySelector(email.AuthPassword), + AuthSecret: credentialToSecretKeySelector(email.AuthSecret), + AuthIdentify: email.AuthIdentify, + RequireTLS: email.RequireTLS, + TLS: convertTLSConfigTo(email.TLS), + } + + return nil +} + +func (src *Config) convertSlackTo(dst *v2beta1.Config) error { + + if src.Spec.Slack == nil { + return nil + } + + slack := src.Spec.Slack + dst.Spec.Slack = &v2beta1.SlackConfig{ + Labels: slack.Labels, + SlackTokenSecret: credentialToSecretKeySelector(slack.SlackTokenSecret), + } + + return nil +} + +func (src *Config) convertWebhookTo(dst *v2beta1.Config) error { + + if src.Spec.Webhook == nil { + return nil + } + + dst.Spec.Webhook = &v2beta1.WebhookConfig{ + Labels: src.Spec.Webhook.Labels, + } + + return nil +} + +func (src *Config) convertWechatTo(dst *v2beta1.Config) error { + + if src.Spec.Wechat == nil { + return nil + } + + wechat := src.Spec.Wechat + dst.Spec.Wechat = &v2beta1.WechatConfig{ + Labels: wechat.Labels, + WechatApiUrl: wechat.WechatApiUrl, + WechatApiCorpId: wechat.WechatApiCorpId, + WechatApiAgentId: wechat.WechatApiAgentId, + WechatApiSecret: credentialToSecretKeySelector(wechat.WechatApiSecret), + } + + return nil +} + +func (dst *Config) convertDingTalkFrom(src *v2beta1.Config) error { + + if src.Spec.DingTalk == nil { + return nil + } + + dingtalk := src.Spec.DingTalk + dst.Spec.DingTalk = &DingTalkConfig{ + Labels: dingtalk.Labels, + } + + if dingtalk.Conversation != nil { + dst.Spec.DingTalk.Conversation = &DingTalkApplicationConfig{ + AppKey: secretKeySelectorToCredential(dingtalk.Conversation.AppKey), + AppSecret: secretKeySelectorToCredential(dingtalk.Conversation.AppSecret), + } + } + + return nil +} + +func (dst *Config) convertEmailFrom(src *v2beta1.Config) error { + + if src.Spec.Email == nil { + return nil + } + + email := src.Spec.Email + dst.Spec.Email = &EmailConfig{ + Labels: email.Labels, + From: email.From, + SmartHost: HostPort{ + Host: email.SmartHost.Host, + Port: email.SmartHost.Port, + }, + Hello: email.Hello, + AuthUsername: email.AuthUsername, + AuthPassword: secretKeySelectorToCredential(email.AuthPassword), + AuthSecret: secretKeySelectorToCredential(email.AuthSecret), + AuthIdentify: email.AuthIdentify, + RequireTLS: email.RequireTLS, + TLS: convertTLSConfigFrom(email.TLS), + } + + return nil +} + +func (dst *Config) convertSlackFrom(src *v2beta1.Config) error { + + if src.Spec.Slack == nil { + return nil + } + + slack := src.Spec.Slack + dst.Spec.Slack = &SlackConfig{ + Labels: slack.Labels, + SlackTokenSecret: secretKeySelectorToCredential(slack.SlackTokenSecret), + } + + return nil +} + +func (dst *Config) convertWebhookFrom(src *v2beta1.Config) error { + + if src.Spec.Webhook == nil { + return nil + } + + dst.Spec.Webhook = &WebhookConfig{ + Labels: src.Spec.Webhook.Labels, + } + + return nil +} + +func (dst *Config) convertWechatFrom(src *v2beta1.Config) error { + + if src.Spec.Wechat == nil { + return nil + } + + wechat := src.Spec.Wechat + dst.Spec.Wechat = &WechatConfig{ + Labels: wechat.Labels, + WechatApiUrl: wechat.WechatApiUrl, + WechatApiCorpId: wechat.WechatApiCorpId, + WechatApiAgentId: wechat.WechatApiAgentId, + WechatApiSecret: secretKeySelectorToCredential(wechat.WechatApiSecret), + } + + return nil +} + +func convertTLSConfigTo(src *TLSConfig) *v2beta1.TLSConfig { + + if src == nil { + return nil + } + + dst := &v2beta1.TLSConfig{ + RootCA: credentialToSecretKeySelector(src.RootCA), + ServerName: src.ServerName, + InsecureSkipVerify: src.InsecureSkipVerify, + } + + if src.ClientCertificate != nil { + dst.ClientCertificate = &v2beta1.ClientCertificate{ + Cert: credentialToSecretKeySelector(src.Cert), + Key: credentialToSecretKeySelector(src.Key), + } + } + + return dst +} + +func convertTLSConfigFrom(src *v2beta1.TLSConfig) *TLSConfig { + + if src == nil { + return nil + } + + dst := &TLSConfig{ + RootCA: secretKeySelectorToCredential(src.RootCA), + ServerName: src.ServerName, + InsecureSkipVerify: src.InsecureSkipVerify, + } + + if src.ClientCertificate != nil { + dst.ClientCertificate = &ClientCertificate{ + Cert: secretKeySelectorToCredential(src.Cert), + Key: secretKeySelectorToCredential(src.Key), + } + } + + return dst +} + +func credentialToSecretKeySelector(src *Credential) *v2beta1.SecretKeySelector { + + if src == nil || src.ValueFrom == nil || src.ValueFrom.SecretKeyRef == nil { + return nil + } + + return &v2beta1.SecretKeySelector{ + Key: src.ValueFrom.SecretKeyRef.Key, + Name: src.ValueFrom.SecretKeyRef.Name, + Namespace: src.ValueFrom.SecretKeyRef.Namespace, + } +} + +func secretKeySelectorToCredential(selector *v2beta1.SecretKeySelector) *Credential { + + if selector == nil { + return nil + } + + return &Credential{ + ValueFrom: &ValueSource{ + SecretKeyRef: &SecretKeySelector{ + Key: selector.Key, + Name: selector.Name, + Namespace: selector.Namespace, + }, + }, + } +} diff --git a/staging/src/kubesphere.io/api/notification/v2beta2/config_types.go b/staging/src/kubesphere.io/api/notification/v2beta2/config_types.go index 1e0a57c43..e6b203f51 100644 --- a/staging/src/kubesphere.io/api/notification/v2beta2/config_types.go +++ b/staging/src/kubesphere.io/api/notification/v2beta2/config_types.go @@ -147,10 +147,18 @@ type HuaweiSMS struct { AppKey *Credential `json:"appKey"` } +// Sms AWS provider parameters +type AWSSMS struct { + Region string `json:"region,omitempty"` + AccessKeyId *Credential `json:"accessKeyId"` + SecretAccessKey *Credential `json:"secretAccessKey"` +} + type Providers struct { Aliyun *AliyunSMS `json:"aliyun,omitempty"` Tencent *TencentSMS `json:"tencent,omitempty"` Huawei *HuaweiSMS `json:"huawei,omitempty"` + AWS *AWSSMS `json:"aws,omitempty"` } type SmsConfig struct { @@ -166,6 +174,14 @@ type PushoverConfig struct { PushoverTokenSecret *Credential `json:"pushoverTokenSecret"` } +// FeishuConfig is the configuration of feishu application +type FeishuConfig struct { + // The id of the application with which to send messages. + AppID *Credential `json:"appID"` + // The key in the secret to be used. Must be a valid secret key. + AppSecret *Credential `json:"appSecret"` +} + //ConfigSpec defines the desired state of Config type ConfigSpec struct { DingTalk *DingTalkConfig `json:"dingtalk,omitempty"` @@ -175,6 +191,7 @@ type ConfigSpec struct { Wechat *WechatConfig `json:"wechat,omitempty"` Sms *SmsConfig `json:"sms,omitempty"` Pushover *PushoverConfig `json:"pushover,omitempty"` + Feishu *FeishuConfig `json:"feishu,omitempty"` } // ConfigStatus defines the observed state of Config @@ -185,8 +202,10 @@ type ConfigStatus struct { // +kubebuilder:resource:scope=Cluster,shortName=nc,categories=notification-manager // +kubebuilder:subresource:status // +kubebuilder:storageversion +// +genclient +// +genclient:nonNamespaced -// Config is the Schema for the dingtalkconfigs API +// Config is the Schema for the configs API type Config struct { metav1.TypeMeta `json:",inline"` metav1.ObjectMeta `json:"metadata,omitempty"` diff --git a/staging/src/kubesphere.io/api/notification/v2beta2/notificationmanager_types.go b/staging/src/kubesphere.io/api/notification/v2beta2/notificationmanager_types.go index de4dad770..61de7b08c 100644 --- a/staging/src/kubesphere.io/api/notification/v2beta2/notificationmanager_types.go +++ b/staging/src/kubesphere.io/api/notification/v2beta2/notificationmanager_types.go @@ -39,6 +39,18 @@ type SecretKeySelector struct { Key string `json:"key" protobuf:"bytes,2,opt,name=key"` } +// ConfigmapKeySelector selects a key of a Configmap. +type ConfigmapKeySelector struct { + // The namespace of the configmap, default to the `defaultSecretNamespace` of `NotificationManager` crd. + // If the `defaultSecretNamespace` does not set, default to the pod's namespace. + // +optional + Namespace string `json:"namespace,omitempty" protobuf:"bytes,1,opt,name=namespace"` + // Name of the configmap. + Name string `json:"name" protobuf:"bytes,1,opt,name=name"` + // The key of the configmap to select from. Must be a valid configmap key. + Key string `json:"key,omitempty" protobuf:"bytes,2,opt,name=key"` +} + type ValueSource struct { // Selects a key of a secret in the pod's namespace // +optional @@ -51,7 +63,7 @@ type Credential struct { ValueFrom *ValueSource `json:"valueFrom,omitempty" protobuf:"bytes,3,opt,name=valueFrom"` } -// Sidecar defines a sidecar container which will be add to the notification manager deployment pod. +// Sidecar defines a sidecar container which will be added to the notification manager deployment pod. type Sidecar struct { // The type of sidecar, it can be specified to any value. // Notification manager built-in sidecar for KubeSphere, @@ -61,6 +73,27 @@ type Sidecar struct { *v1.Container `json:",inline"` } +// HistoryReceiver used to collect notification history. +type HistoryReceiver struct { + // Use a webhook to collect notification history, it will create a virtual receiver. + Webhook *WebhookReceiver `json:"webhook"` +} + +type Template struct { + // Template file. + Text *ConfigmapKeySelector `json:"text,omitempty"` + // Time to reload template file. + // + // +kubebuilder:default="1m" + ReloadCycle metav1.Duration `json:"reloadCycle,omitempty"` + // Configmap which the i18n file be in. + LanguagePack []*ConfigmapKeySelector `json:"languagePack,omitempty"` + // The language used to send notification. + // + // +kubebuilder:default="English" + Language string `json:"language,omitempty"` +} + // NotificationManagerSpec defines the desired state of NotificationManager type NotificationManagerSpec struct { // Compute Resources required by container. @@ -84,7 +117,7 @@ type NotificationManagerSpec struct { ServiceAccountName string `json:"serviceAccountName,omitempty"` // Port name used for the pods and service, defaults to webhook PortName string `json:"portName,omitempty"` - // Default Email/Wechat/Slack/Webhook Config to be selected + // Default Email/WeChat/Slack/Webhook Config to be selected DefaultConfigSelector *metav1.LabelSelector `json:"defaultConfigSelector,omitempty"` // Receivers to send notifications to Receivers *ReceiversSpec `json:"receivers"` @@ -104,6 +137,30 @@ type NotificationManagerSpec struct { // It needs to provide the API `/api/v2/tenant` at port `19094`, this api receives // a parameter `namespace` and return all tenants which need to receive notifications in this namespace. Sidecars map[string]*Sidecar `json:"sidecars,omitempty"` + // History used to collect notification history. + History *HistoryReceiver `json:"history,omitempty"` + // Labels for grouping notifiations. + GroupLabels []string `json:"groupLabels,omitempty"` + // The maximum size of a batch. A batch used to buffer alerts and asynchronously process them. + // + // +kubebuilder:default=100 + BatchMaxSize int `json:"batchMaxSize,omitempty"` + // The amount of time to wait before force processing the batch that hadn't reached the max size. + // + // +kubebuilder:default="1m" + BatchMaxWait metav1.Duration `json:"batchMaxWait,omitempty"` + // The RoutePolicy determines how to find receivers to which notifications will be sent. + // Valid RoutePolicy include All, RouterFirst, and RouterOnly. + // All: The alerts will be sent to the receivers that match any router, + // and also will be sent to the receivers of those tenants with the right to access the namespace to which the alert belongs. + // RouterFirst: The alerts will be sent to the receivers that match any router first. + // If no receivers match any router, alerts will send to the receivers of those tenants with the right to access the namespace to which the alert belongs. + // RouterOnly: The alerts will only be sent to the receivers that match any router. + // + // +kubebuilder:default=All + RoutePolicy string `json:"routePolicy,omitempty"` + // Template used to define information about templates + Template *Template `json:"template,omitempty"` } type ReceiversSpec struct { @@ -121,7 +178,9 @@ type ReceiversSpec struct { } type GlobalOptions struct { - // Template file path, must be a absolute path. + // Template file path, must be an absolute path. + // + // Deprecated TemplateFiles []string `json:"templateFile,omitempty"` // The name of the template to generate message. // If the receiver dose not setup template, it will use this. @@ -149,7 +208,7 @@ type EmailOptions struct { type WechatOptions struct { // Notification Sending Timeout NotificationTimeout *int32 `json:"notificationTimeout,omitempty"` - // The name of the template to generate wechat message. + // The name of the template to generate WeChat message. Template string `json:"template,omitempty"` // template type: text or markdown, default type is text TmplType string `json:"tmplType,omitempty"` @@ -162,7 +221,7 @@ type WechatOptions struct { type SlackOptions struct { // Notification Sending Timeout NotificationTimeout *int32 `json:"notificationTimeout,omitempty"` - // The name of the template to generate slack message. + // The name of the template to generate Slack message. // If the global template is not set, it will use default. Template string `json:"template,omitempty"` } @@ -181,7 +240,7 @@ type Throttle struct { Threshold int `json:"threshold,omitempty"` Unit time.Duration `json:"unit,omitempty"` // The maximum tolerable waiting time when the calls trigger flow control, if the actual waiting time is more than this time, it will - // return a error, else it will wait for the flow restriction lifted, and send the message. + // return an error, else it will wait for the flow restriction lifted, and send the message. // Nil means do not wait, the maximum value is `Unit`. MaxWaitTime time.Duration `json:"maxWaitTime,omitempty"` } @@ -202,9 +261,9 @@ type DingTalkOptions struct { ConversationMessageMaxSize int `json:"conversationMessageMaxSize,omitempty"` // The maximum message size that can be sent to chatbot in a request. ChatbotMessageMaxSize int `json:"chatbotMessageMaxSize,omitempty"` - // The flow control fo chatbot. + // The flow control for chatbot. ChatBotThrottle *Throttle `json:"chatBotThrottle,omitempty"` - // The flow control fo conversation. + // The flow control for conversation. ConversationThrottle *Throttle `json:"conversationThrottle,omitempty"` } @@ -222,6 +281,20 @@ type PushoverOptions struct { // The name of the template to generate pushover message. // If the global template is not set, it will use default. Template string `json:"template,omitempty"` + // The name of the template to generate message title + TitleTemplate string `json:"titleTemplate,omitempty"` +} + +type FeishuOptions struct { + // Notification Sending Timeout + NotificationTimeout *int32 `json:"notificationTimeout,omitempty"` + // The name of the template to generate DingTalk message. + // If the global template is not set, it will use default. + Template string `json:"template,omitempty"` + // template type: text or post, default type is post + TmplType string `json:"tmplType,omitempty"` + // The time of token expired. + TokenExpires time.Duration `json:"tokenExpires,omitempty"` } type Options struct { @@ -233,6 +306,7 @@ type Options struct { DingTalk *DingTalkOptions `json:"dingtalk,omitempty"` Sms *SmsOptions `json:"sms,omitempty"` Pushover *PushoverOptions `json:"pushover,omitempty"` + Feishu *FeishuOptions `json:"feishu,omitempty"` } // NotificationManagerStatus defines the observed state of NotificationManager diff --git a/staging/src/kubesphere.io/api/notification/v2beta2/receiver_conversion.go b/staging/src/kubesphere.io/api/notification/v2beta2/receiver_conversion.go new file mode 100644 index 000000000..066bc2488 --- /dev/null +++ b/staging/src/kubesphere.io/api/notification/v2beta2/receiver_conversion.go @@ -0,0 +1,330 @@ +/* + + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v2beta2 + +import ( + "kubesphere.io/api/notification/v2beta1" + "sigs.k8s.io/controller-runtime/pkg/conversion" +) + +// ConvertTo converts this Config to the Hub version (v2beta1). +func (src *Receiver) ConvertTo(dstRaw conversion.Hub) error { + + dst := dstRaw.(*v2beta1.Receiver) + dst.ObjectMeta = src.ObjectMeta + + if err := src.convertDingTalkTo(dst); err != nil { + return err + } + + if err := src.convertEmailTo(dst); err != nil { + return err + } + + if err := src.convertSlackTo(dst); err != nil { + return err + } + + if err := src.convertWebhookTo(dst); err != nil { + return err + } + + if err := src.convertWechatTo(dst); err != nil { + return err + } + + return nil +} + +// ConvertFrom converts from the Hub version (v2beta1) to this version. +func (dst *Receiver) ConvertFrom(srcRaw conversion.Hub) error { + + src := srcRaw.(*v2beta1.Receiver) + dst.ObjectMeta = src.ObjectMeta + + if err := dst.convertDingTalkFrom(src); err != nil { + return err + } + + if err := dst.convertEmailFrom(src); err != nil { + return err + } + + if err := dst.convertSlackFrom(src); err != nil { + return err + } + + if err := dst.convertWebhookFrom(src); err != nil { + return err + } + + if err := dst.convertWechatFrom(src); err != nil { + return err + } + + return nil +} + +func (src *Receiver) convertDingTalkTo(dst *v2beta1.Receiver) error { + + if src.Spec.DingTalk == nil { + return nil + } + + dingtalk := src.Spec.DingTalk + dst.Spec.DingTalk = &v2beta1.DingTalkReceiver{ + Enabled: dingtalk.Enabled, + DingTalkConfigSelector: dingtalk.DingTalkConfigSelector, + AlertSelector: dingtalk.AlertSelector, + } + + if dingtalk.Conversation != nil { + dst.Spec.DingTalk.Conversation = &v2beta1.DingTalkConversation{ + ChatIDs: dingtalk.Conversation.ChatIDs, + } + } + + if dingtalk.ChatBot != nil { + dst.Spec.DingTalk.ChatBot = &v2beta1.DingTalkChatBot{ + Webhook: credentialToSecretKeySelector(dingtalk.ChatBot.Webhook), + Keywords: dingtalk.ChatBot.Keywords, + Secret: credentialToSecretKeySelector(dingtalk.ChatBot.Secret), + } + } + + return nil +} + +func (src *Receiver) convertEmailTo(dst *v2beta1.Receiver) error { + + if src.Spec.Email == nil { + return nil + } + + email := src.Spec.Email + dst.Spec.Email = &v2beta1.EmailReceiver{ + Enabled: email.Enabled, + To: email.To, + EmailConfigSelector: email.EmailConfigSelector, + AlertSelector: email.AlertSelector, + } + + return nil +} + +func (src *Receiver) convertSlackTo(dst *v2beta1.Receiver) error { + + if src.Spec.Slack == nil { + return nil + } + + slack := src.Spec.Slack + dst.Spec.Slack = &v2beta1.SlackReceiver{ + Enabled: slack.Enabled, + SlackConfigSelector: slack.SlackConfigSelector, + AlertSelector: slack.AlertSelector, + Channels: slack.Channels, + } + + return nil +} + +func (src *Receiver) convertWebhookTo(dst *v2beta1.Receiver) error { + + if src.Spec.Webhook == nil { + return nil + } + + webhook := src.Spec.Webhook + dst.Spec.Webhook = &v2beta1.WebhookReceiver{ + Enabled: webhook.Enabled, + WebhookConfigSelector: webhook.WebhookConfigSelector, + AlertSelector: webhook.AlertSelector, + URL: webhook.URL, + } + + if webhook.Service != nil { + dst.Spec.Webhook.Service = &v2beta1.ServiceReference{ + Namespace: webhook.Service.Namespace, + Name: webhook.Service.Name, + Path: webhook.Service.Path, + Port: webhook.Service.Port, + Scheme: webhook.Service.Scheme, + } + } + + if webhook.HTTPConfig != nil { + dst.Spec.Webhook.HTTPConfig = &v2beta1.HTTPClientConfig{ + BearerToken: credentialToSecretKeySelector(webhook.HTTPConfig.BearerToken), + ProxyURL: webhook.HTTPConfig.ProxyURL, + TLSConfig: convertTLSConfigTo(webhook.HTTPConfig.TLSConfig), + } + + if webhook.HTTPConfig.BasicAuth != nil { + dst.Spec.Webhook.HTTPConfig.BasicAuth = &v2beta1.BasicAuth{ + Username: webhook.HTTPConfig.BasicAuth.Username, + Password: credentialToSecretKeySelector(webhook.HTTPConfig.BasicAuth.Password), + } + } + } + + return nil +} + +func (src *Receiver) convertWechatTo(dst *v2beta1.Receiver) error { + + if src.Spec.Wechat == nil { + return nil + } + + wechat := src.Spec.Wechat + dst.Spec.Wechat = &v2beta1.WechatReceiver{ + Enabled: wechat.Enabled, + WechatConfigSelector: wechat.WechatConfigSelector, + AlertSelector: wechat.AlertSelector, + ToUser: wechat.ToUser, + ToParty: wechat.ToParty, + ToTag: wechat.ToTag, + } + + return nil +} + +func (dst *Receiver) convertDingTalkFrom(src *v2beta1.Receiver) error { + + if src.Spec.DingTalk == nil { + return nil + } + + dingtalk := src.Spec.DingTalk + dst.Spec.DingTalk = &DingTalkReceiver{ + Enabled: dingtalk.Enabled, + DingTalkConfigSelector: dingtalk.DingTalkConfigSelector, + AlertSelector: dingtalk.AlertSelector, + } + + if dingtalk.Conversation != nil { + dst.Spec.DingTalk.Conversation = &DingTalkConversation{ + ChatIDs: dingtalk.Conversation.ChatIDs, + } + } + + if dingtalk.ChatBot != nil { + dst.Spec.DingTalk.ChatBot = &DingTalkChatBot{ + Webhook: secretKeySelectorToCredential(dingtalk.ChatBot.Webhook), + Keywords: dingtalk.ChatBot.Keywords, + Secret: secretKeySelectorToCredential(dingtalk.ChatBot.Secret), + } + } + + return nil +} + +func (dst *Receiver) convertEmailFrom(src *v2beta1.Receiver) error { + + if src.Spec.Email == nil { + return nil + } + + email := src.Spec.Email + dst.Spec.Email = &EmailReceiver{ + Enabled: email.Enabled, + To: email.To, + EmailConfigSelector: email.EmailConfigSelector, + AlertSelector: email.AlertSelector, + } + + return nil +} + +func (dst *Receiver) convertSlackFrom(src *v2beta1.Receiver) error { + + if src.Spec.Slack == nil { + return nil + } + + slack := src.Spec.Slack + dst.Spec.Slack = &SlackReceiver{ + Enabled: slack.Enabled, + SlackConfigSelector: slack.SlackConfigSelector, + AlertSelector: slack.AlertSelector, + Channels: slack.Channels, + } + + return nil +} + +func (dst *Receiver) convertWebhookFrom(src *v2beta1.Receiver) error { + + if src.Spec.Webhook == nil { + return nil + } + + webhook := src.Spec.Webhook + dst.Spec.Webhook = &WebhookReceiver{ + Enabled: webhook.Enabled, + WebhookConfigSelector: webhook.WebhookConfigSelector, + AlertSelector: webhook.AlertSelector, + URL: webhook.URL, + } + + if webhook.Service != nil { + dst.Spec.Webhook.Service = &ServiceReference{ + Namespace: webhook.Service.Namespace, + Name: webhook.Service.Name, + Path: webhook.Service.Path, + Port: webhook.Service.Port, + Scheme: webhook.Service.Scheme, + } + } + + if webhook.HTTPConfig != nil { + dst.Spec.Webhook.HTTPConfig = &HTTPClientConfig{ + BearerToken: secretKeySelectorToCredential(webhook.HTTPConfig.BearerToken), + ProxyURL: webhook.HTTPConfig.ProxyURL, + TLSConfig: convertTLSConfigFrom(webhook.HTTPConfig.TLSConfig), + } + + if webhook.HTTPConfig.BasicAuth != nil { + dst.Spec.Webhook.HTTPConfig.BasicAuth = &BasicAuth{ + Username: webhook.HTTPConfig.BasicAuth.Username, + Password: secretKeySelectorToCredential(webhook.HTTPConfig.BasicAuth.Password), + } + } + } + + return nil +} + +func (dst *Receiver) convertWechatFrom(src *v2beta1.Receiver) error { + + if src.Spec.Wechat == nil { + return nil + } + + wechat := src.Spec.Wechat + dst.Spec.Wechat = &WechatReceiver{ + Enabled: wechat.Enabled, + WechatConfigSelector: wechat.WechatConfigSelector, + AlertSelector: wechat.AlertSelector, + ToUser: wechat.ToUser, + ToParty: wechat.ToParty, + ToTag: wechat.ToTag, + } + + return nil +} diff --git a/staging/src/kubesphere.io/api/notification/v2beta2/receiver_types.go b/staging/src/kubesphere.io/api/notification/v2beta2/receiver_types.go index 87ca0b09a..e636992db 100644 --- a/staging/src/kubesphere.io/api/notification/v2beta2/receiver_types.go +++ b/staging/src/kubesphere.io/api/notification/v2beta2/receiver_types.go @@ -54,13 +54,15 @@ type DingTalkReceiver struct { ChatBot *DingTalkChatBot `json:"chatbot,omitempty"` // The conversation which message will send to. Conversation *DingTalkConversation `json:"conversation,omitempty"` - // The name of the template to generate DingTalk message. + // The name of the template to generate notification. // If the global template is not set, it will use default. Template *string `json:"template,omitempty"` // The name of the template to generate markdown title TitleTemplate *string `json:"titleTemplate,omitempty"` // template type: text or markdown TmplType *string `json:"tmplType,omitempty"` + // Template file. + TmplText *ConfigmapKeySelector `json:"tmplText,omitempty"` } type EmailReceiver struct { @@ -72,13 +74,15 @@ type EmailReceiver struct { EmailConfigSelector *metav1.LabelSelector `json:"emailConfigSelector,omitempty"` // Selector to filter alerts. AlertSelector *metav1.LabelSelector `json:"alertSelector,omitempty"` - // The name of the template to generate DingTalk message. + // The name of the template to generate notification. // If the global template is not set, it will use default. Template *string `json:"template,omitempty"` // The name of the template to generate email subject SubjectTemplate *string `json:"subjectTemplate,omitempty"` // template type: text or html, default type is html TmplType *string `json:"tmplType,omitempty"` + // Template file. + TmplText *ConfigmapKeySelector `json:"tmplText,omitempty"` } type SlackReceiver struct { @@ -90,9 +94,11 @@ type SlackReceiver struct { AlertSelector *metav1.LabelSelector `json:"alertSelector,omitempty"` // The channel or user to send notifications to. Channels []string `json:"channels"` - // The name of the template to generate DingTalk message. + // The name of the template to generate notification. // If the global template is not set, it will use default. Template *string `json:"template,omitempty"` + // Template file. + TmplText *ConfigmapKeySelector `json:"tmplText,omitempty"` } // ServiceReference holds a reference to Service.legacy.k8s.io @@ -164,9 +170,11 @@ type WebhookReceiver struct { Service *ServiceReference `json:"service,omitempty"` HTTPConfig *HTTPClientConfig `json:"httpConfig,omitempty"` - // The name of the template to generate DingTalk message. + // The name of the template to generate notification. // If the global template is not set, it will use default. Template *string `json:"template,omitempty"` + // Template file. + TmplText *ConfigmapKeySelector `json:"tmplText,omitempty"` } type WechatReceiver struct { @@ -180,11 +188,13 @@ type WechatReceiver struct { ToUser []string `json:"toUser,omitempty"` ToParty []string `json:"toParty,omitempty"` ToTag []string `json:"toTag,omitempty"` - // The name of the template to generate DingTalk message. + // The name of the template to generate notification. // If the global template is not set, it will use default. Template *string `json:"template,omitempty"` // template type: text or markdown, default type is text TmplType *string `json:"tmplType,omitempty"` + // Template file. + TmplText *ConfigmapKeySelector `json:"tmplText,omitempty"` } type SmsReceiver struct { @@ -196,9 +206,11 @@ type SmsReceiver struct { AlertSelector *metav1.LabelSelector `json:"alertSelector,omitempty"` // Receivers' phone numbers PhoneNumbers []string `json:"phoneNumbers"` - // The name of the template to generate Sms message. + // The name of the template to generate notification. // If the global template is not set, it will use default. Template *string `json:"template,omitempty"` + // Template file. + TmplText *ConfigmapKeySelector `json:"tmplText,omitempty"` } // PushoverUserProfile includes userKey and other preferences @@ -209,6 +221,9 @@ type PushoverUserProfile struct { // Devices refers to device name to send the message directly to that device, rather than all of the user's devices Devices []string `json:"devices,omitempty"` // Title refers to message's title, otherwise your app's name is used. + // it is deprecated, now the title will be generated by the title template. + // + // Deprecated Title *string `json:"title,omitempty"` // Sound refers to the name of one of the sounds (https://pushover.net/api#sounds) supported by device clients Sound *string `json:"sound,omitempty"` @@ -221,11 +236,50 @@ type PushoverReceiver struct { PushoverConfigSelector *metav1.LabelSelector `json:"pushoverConfigSelector,omitempty"` // Selector to filter alerts. AlertSelector *metav1.LabelSelector `json:"alertSelector,omitempty"` - // The name of the template to generate DingTalk message. + // The name of the template to generate notification. // If the global template is not set, it will use default. Template *string `json:"template,omitempty"` + // The name of the template to generate message title + TitleTemplate *string `json:"titleTemplate,omitempty"` // The users profile. Profiles []*PushoverUserProfile `json:"profiles"` + // Template file. + TmplText *ConfigmapKeySelector `json:"tmplText,omitempty"` +} + +// FeishuChatBot is the configuration of ChatBot +type FeishuChatBot struct { + // The webhook of the ChatBot to which the message will be sent. + Webhook *Credential `json:"webhook"` + + // Custom keywords of ChatBot + Keywords []string `json:"keywords,omitempty"` + + // Secret of ChatBot, you can get it after enabling signature verification of ChatBot. + Secret *Credential `json:"secret,omitempty"` +} + +type FeishuReceiver struct { + // whether the receiver is enabled + Enabled *bool `json:"enabled,omitempty"` + // FeishuConfig to be selected for this receiver + FeishuConfigSelector *metav1.LabelSelector `json:"feishuConfigSelector,omitempty"` + // Selector to filter alerts. + AlertSelector *metav1.LabelSelector `json:"alertSelector,omitempty"` + // +optional + // +kubebuilder:validation:MaxItems=200 + User []string `json:"user,omitempty"` + // +optional + // +kubebuilder:validation:MaxItems=200 + Department []string `json:"department,omitempty"` + ChatBot *FeishuChatBot `json:"chatbot,omitempty"` + // The name of the template to generate notification. + // If the global template is not set, it will use default. + Template *string `json:"template,omitempty"` + // template type: text or post, default type is post + TmplType *string `json:"tmplType,omitempty"` + // Template file. + TmplText *ConfigmapKeySelector `json:"tmplText,omitempty"` } //ReceiverSpec defines the desired state of Receiver @@ -237,6 +291,7 @@ type ReceiverSpec struct { Wechat *WechatReceiver `json:"wechat,omitempty"` Sms *SmsReceiver `json:"sms,omitempty"` Pushover *PushoverReceiver `json:"pushover,omitempty"` + Feishu *FeishuReceiver `json:"feishu,omitempty"` } // ReceiverStatus defines the observed state of Receiver @@ -247,7 +302,8 @@ type ReceiverStatus struct { // +kubebuilder:resource:scope=Cluster,shortName=nr,categories=notification-manager // +kubebuilder:subresource:status // +kubebuilder:storageversion - +// +genclient +// +genclient:nonNamespaced // Receiver is the Schema for the receivers API type Receiver struct { metav1.TypeMeta `json:",inline"` diff --git a/staging/src/kubesphere.io/api/notification/v2beta2/register.go b/staging/src/kubesphere.io/api/notification/v2beta2/register.go index 34dfb4227..7bccd2e2b 100644 --- a/staging/src/kubesphere.io/api/notification/v2beta2/register.go +++ b/staging/src/kubesphere.io/api/notification/v2beta2/register.go @@ -15,7 +15,7 @@ limitations under the License. */ // Package v2beta2 contains API Schema definitions for the notification v1alpha1 API group -// +kubebuilder:object:generate=true +// +k8s:deepcopy-gen=package,register // +groupName=notification.kubesphere.io package v2beta2 @@ -26,15 +26,15 @@ import ( var ( // GroupVersion is group version used to register these objects - GroupVersion = schema.GroupVersion{Group: "notification.kubesphere.io", Version: "v2beta2"} + SchemeGroupVersion = schema.GroupVersion{Group: "notification.kubesphere.io", Version: "v2beta2"} // SchemeBuilder is used to add go types to the GroupVersionKind scheme - SchemeBuilder = &scheme.Builder{GroupVersion: GroupVersion} + SchemeBuilder = &scheme.Builder{GroupVersion: SchemeGroupVersion} // AddToScheme adds the types in this group-version to the given scheme. AddToScheme = SchemeBuilder.AddToScheme ) func Resource(resource string) schema.GroupResource { - return GroupVersion.WithResource(resource).GroupResource() + return SchemeGroupVersion.WithResource(resource).GroupResource() } diff --git a/staging/src/kubesphere.io/api/notification/v2beta2/router_types.go b/staging/src/kubesphere.io/api/notification/v2beta2/router_types.go new file mode 100644 index 000000000..aa46ee99a --- /dev/null +++ b/staging/src/kubesphere.io/api/notification/v2beta2/router_types.go @@ -0,0 +1,70 @@ +/* + + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v2beta2 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +type ReceiverSelector struct { + Name []string `json:"name,omitempty"` + RegexName string `json:"regexName,omitempty"` + Selector *metav1.LabelSelector `json:"selector,omitempty"` + // Receiver type, known values are dingtalk, email, slack, sms, pushover, webhook, wechat. + Type string `json:"type,omitempty"` +} + +// RouterSpec defines the desired state of Router +type RouterSpec struct { + // whether the router is enabled + Enabled *bool `json:"enabled,omitempty"` + AlertSelector *metav1.LabelSelector `json:"alertSelector"` + // Receivers which need to receive the matched alert. + Receivers ReceiverSelector `json:"receivers"` +} + +// RouterStatus defines the observed state of Router +type RouterStatus struct { +} + +// +kubebuilder:object:root=true +// +kubebuilder:resource:scope=Cluster,categories=notification-manager +// +kubebuilder:subresource:status +// +kubebuilder:storageversion +// +genclient +// +genclient:nonNamespaced +// Router is the Schema for the router API +type Router struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec RouterSpec `json:"spec,omitempty"` + Status RouterStatus `json:"status,omitempty"` +} + +// +kubebuilder:object:root=true + +// RouterList contains a list of Router +type RouterList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []Router `json:"items"` +} + +func init() { + SchemeBuilder.Register(&Router{}, &RouterList{}) +} diff --git a/staging/src/kubesphere.io/api/notification/v2beta2/silence_types.go b/staging/src/kubesphere.io/api/notification/v2beta2/silence_types.go new file mode 100644 index 000000000..b8294ea88 --- /dev/null +++ b/staging/src/kubesphere.io/api/notification/v2beta2/silence_types.go @@ -0,0 +1,111 @@ +/* + + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v2beta2 + +import ( + "time" + + "github.com/robfig/cron/v3" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// SilenceSpec defines the desired state of Silence +type SilenceSpec struct { + // whether the silence is enabled + Enabled *bool `json:"enabled,omitempty"` + Matcher *metav1.LabelSelector `json:"matcher"` + // The start time during which the silence is active. + // + // +kubebuilder:validation:Format: date-time + StartsAt *metav1.Time `json:"startsAt,omitempty"` + // The schedule in Cron format. + // If set the silence will be active periodicity, and the startsAt will be invalid. + Schedule string `json:"schedule,omitempty"` + // The time range during which the silence is active. + // If not set, the silence will be active ever. + Duration *metav1.Duration `json:"duration,omitempty"` +} + +// SilenceStatus defines the observed state of Silence +type SilenceStatus struct { +} + +// +kubebuilder:object:root=true +// +kubebuilder:resource:scope=Cluster,categories=notification-manager +// +kubebuilder:subresource:status +// +kubebuilder:storageversion +// +genclient +// +genclient:nonNamespaced + +// Silence is the Schema for the Silence API +type Silence struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec SilenceSpec `json:"spec,omitempty"` + Status SilenceStatus `json:"status,omitempty"` +} + +// +kubebuilder:object:root=true + +// SilenceList contains a list of Silence +type SilenceList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []Silence `json:"items"` +} + +func init() { + SchemeBuilder.Register(&Silence{}, &SilenceList{}) +} + +func (s *Silence) IsActive() bool { + + if s.Spec.Enabled != nil && !*s.Spec.Enabled { + return false + } + + if s.Spec.Schedule != "" { + + if s.Spec.Duration == nil { + return true + } + + schedule, _ := cron.ParseStandard(s.Spec.Schedule) + if schedule.Next(time.Now()) == schedule.Next(time.Now().Add(-(*s.Spec.Duration).Duration)) { + return false + } else { + return true + } + } else if s.Spec.StartsAt != nil { + if s.Spec.StartsAt.After(time.Now()) { + return false + } + + if s.Spec.Duration == nil { + return true + } + + if s.Spec.StartsAt.Add((*s.Spec.Duration).Duration).After(time.Now()) { + return true + } + + return false + } else { + return true + } +} diff --git a/staging/src/kubesphere.io/api/notification/v2beta2/types.go b/staging/src/kubesphere.io/api/notification/v2beta2/types.go index 0c4f29c99..2f929381d 100644 --- a/staging/src/kubesphere.io/api/notification/v2beta2/types.go +++ b/staging/src/kubesphere.io/api/notification/v2beta2/types.go @@ -24,4 +24,12 @@ const ( ResourceKindReceiver = "Receiver" ResourcesSingularReceiver = "receiver" ResourcesPluralReceiver = "receivers" + + ResourceKindRouter = "Router" + ResourcesSingularRouter = "router" + ResourcesPluralRouter = "routers" + + ResourceKindSilence = "Silence" + ResourcesSingularSilence = "silence" + ResourcesPluralSilence = "silences" ) diff --git a/staging/src/kubesphere.io/api/notification/v2beta2/zz_generated.deepcopy.go b/staging/src/kubesphere.io/api/notification/v2beta2/zz_generated.deepcopy.go index 250573a4a..fec50b656 100644 --- a/staging/src/kubesphere.io/api/notification/v2beta2/zz_generated.deepcopy.go +++ b/staging/src/kubesphere.io/api/notification/v2beta2/zz_generated.deepcopy.go @@ -26,6 +26,31 @@ import ( "k8s.io/apimachinery/pkg/runtime" ) +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *AWSSMS) DeepCopyInto(out *AWSSMS) { + *out = *in + if in.AccessKeyId != nil { + in, out := &in.AccessKeyId, &out.AccessKeyId + *out = new(Credential) + (*in).DeepCopyInto(*out) + } + if in.SecretAccessKey != nil { + in, out := &in.SecretAccessKey, &out.SecretAccessKey + *out = new(Credential) + (*in).DeepCopyInto(*out) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AWSSMS. +func (in *AWSSMS) DeepCopy() *AWSSMS { + if in == nil { + return nil + } + out := new(AWSSMS) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *AliyunSMS) DeepCopyInto(out *AliyunSMS) { *out = *in @@ -193,6 +218,11 @@ func (in *ConfigSpec) DeepCopyInto(out *ConfigSpec) { *out = new(PushoverConfig) (*in).DeepCopyInto(*out) } + if in.Feishu != nil { + in, out := &in.Feishu, &out.Feishu + *out = new(FeishuConfig) + (*in).DeepCopyInto(*out) + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ConfigSpec. @@ -220,6 +250,21 @@ func (in *ConfigStatus) DeepCopy() *ConfigStatus { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ConfigmapKeySelector) DeepCopyInto(out *ConfigmapKeySelector) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ConfigmapKeySelector. +func (in *ConfigmapKeySelector) DeepCopy() *ConfigmapKeySelector { + if in == nil { + return nil + } + out := new(ConfigmapKeySelector) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *Credential) DeepCopyInto(out *Credential) { *out = *in @@ -425,6 +470,11 @@ func (in *DingTalkReceiver) DeepCopyInto(out *DingTalkReceiver) { *out = new(string) **out = **in } + if in.TmplText != nil { + in, out := &in.TmplText, &out.TmplText + *out = new(ConfigmapKeySelector) + **out = **in + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DingTalkReceiver. @@ -553,6 +603,11 @@ func (in *EmailReceiver) DeepCopyInto(out *EmailReceiver) { *out = new(string) **out = **in } + if in.TmplText != nil { + in, out := &in.TmplText, &out.TmplText + *out = new(ConfigmapKeySelector) + **out = **in + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new EmailReceiver. @@ -565,6 +620,141 @@ func (in *EmailReceiver) DeepCopy() *EmailReceiver { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *FeishuChatBot) DeepCopyInto(out *FeishuChatBot) { + *out = *in + if in.Webhook != nil { + in, out := &in.Webhook, &out.Webhook + *out = new(Credential) + (*in).DeepCopyInto(*out) + } + if in.Keywords != nil { + in, out := &in.Keywords, &out.Keywords + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.Secret != nil { + in, out := &in.Secret, &out.Secret + *out = new(Credential) + (*in).DeepCopyInto(*out) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FeishuChatBot. +func (in *FeishuChatBot) DeepCopy() *FeishuChatBot { + if in == nil { + return nil + } + out := new(FeishuChatBot) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *FeishuConfig) DeepCopyInto(out *FeishuConfig) { + *out = *in + if in.AppID != nil { + in, out := &in.AppID, &out.AppID + *out = new(Credential) + (*in).DeepCopyInto(*out) + } + if in.AppSecret != nil { + in, out := &in.AppSecret, &out.AppSecret + *out = new(Credential) + (*in).DeepCopyInto(*out) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FeishuConfig. +func (in *FeishuConfig) DeepCopy() *FeishuConfig { + if in == nil { + return nil + } + out := new(FeishuConfig) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *FeishuOptions) DeepCopyInto(out *FeishuOptions) { + *out = *in + if in.NotificationTimeout != nil { + in, out := &in.NotificationTimeout, &out.NotificationTimeout + *out = new(int32) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FeishuOptions. +func (in *FeishuOptions) DeepCopy() *FeishuOptions { + if in == nil { + return nil + } + out := new(FeishuOptions) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *FeishuReceiver) DeepCopyInto(out *FeishuReceiver) { + *out = *in + if in.Enabled != nil { + in, out := &in.Enabled, &out.Enabled + *out = new(bool) + **out = **in + } + if in.FeishuConfigSelector != nil { + in, out := &in.FeishuConfigSelector, &out.FeishuConfigSelector + *out = new(metav1.LabelSelector) + (*in).DeepCopyInto(*out) + } + if in.AlertSelector != nil { + in, out := &in.AlertSelector, &out.AlertSelector + *out = new(metav1.LabelSelector) + (*in).DeepCopyInto(*out) + } + if in.User != nil { + in, out := &in.User, &out.User + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.Department != nil { + in, out := &in.Department, &out.Department + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.ChatBot != nil { + in, out := &in.ChatBot, &out.ChatBot + *out = new(FeishuChatBot) + (*in).DeepCopyInto(*out) + } + if in.Template != nil { + in, out := &in.Template, &out.Template + *out = new(string) + **out = **in + } + if in.TmplType != nil { + in, out := &in.TmplType, &out.TmplType + *out = new(string) + **out = **in + } + if in.TmplText != nil { + in, out := &in.TmplText, &out.TmplText + *out = new(ConfigmapKeySelector) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FeishuReceiver. +func (in *FeishuReceiver) DeepCopy() *FeishuReceiver { + if in == nil { + return nil + } + out := new(FeishuReceiver) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *GlobalOptions) DeepCopyInto(out *GlobalOptions) { *out = *in @@ -615,6 +805,26 @@ func (in *HTTPClientConfig) DeepCopy() *HTTPClientConfig { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *HistoryReceiver) DeepCopyInto(out *HistoryReceiver) { + *out = *in + if in.Webhook != nil { + in, out := &in.Webhook, &out.Webhook + *out = new(WebhookReceiver) + (*in).DeepCopyInto(*out) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HistoryReceiver. +func (in *HistoryReceiver) DeepCopy() *HistoryReceiver { + if in == nil { + return nil + } + out := new(HistoryReceiver) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *HostPort) DeepCopyInto(out *HostPort) { *out = *in @@ -796,6 +1006,22 @@ func (in *NotificationManagerSpec) DeepCopyInto(out *NotificationManagerSpec) { (*out)[key] = outVal } } + if in.History != nil { + in, out := &in.History, &out.History + *out = new(HistoryReceiver) + (*in).DeepCopyInto(*out) + } + if in.GroupLabels != nil { + in, out := &in.GroupLabels, &out.GroupLabels + *out = make([]string, len(*in)) + copy(*out, *in) + } + out.BatchMaxWait = in.BatchMaxWait + if in.Template != nil { + in, out := &in.Template, &out.Template + *out = new(Template) + (*in).DeepCopyInto(*out) + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NotificationManagerSpec. @@ -866,6 +1092,11 @@ func (in *Options) DeepCopyInto(out *Options) { *out = new(PushoverOptions) (*in).DeepCopyInto(*out) } + if in.Feishu != nil { + in, out := &in.Feishu, &out.Feishu + *out = new(FeishuOptions) + (*in).DeepCopyInto(*out) + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Options. @@ -896,6 +1127,11 @@ func (in *Providers) DeepCopyInto(out *Providers) { *out = new(HuaweiSMS) (*in).DeepCopyInto(*out) } + if in.AWS != nil { + in, out := &in.AWS, &out.AWS + *out = new(AWSSMS) + (*in).DeepCopyInto(*out) + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Providers. @@ -978,6 +1214,11 @@ func (in *PushoverReceiver) DeepCopyInto(out *PushoverReceiver) { *out = new(string) **out = **in } + if in.TitleTemplate != nil { + in, out := &in.TitleTemplate, &out.TitleTemplate + *out = new(string) + **out = **in + } if in.Profiles != nil { in, out := &in.Profiles, &out.Profiles *out = make([]*PushoverUserProfile, len(*in)) @@ -989,6 +1230,11 @@ func (in *PushoverReceiver) DeepCopyInto(out *PushoverReceiver) { } } } + if in.TmplText != nil { + in, out := &in.TmplText, &out.TmplText + *out = new(ConfigmapKeySelector) + **out = **in + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PushoverReceiver. @@ -1095,6 +1341,31 @@ func (in *ReceiverList) DeepCopyObject() runtime.Object { return nil } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ReceiverSelector) DeepCopyInto(out *ReceiverSelector) { + *out = *in + if in.Name != nil { + in, out := &in.Name, &out.Name + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.Selector != nil { + in, out := &in.Selector, &out.Selector + *out = new(metav1.LabelSelector) + (*in).DeepCopyInto(*out) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ReceiverSelector. +func (in *ReceiverSelector) DeepCopy() *ReceiverSelector { + if in == nil { + return nil + } + out := new(ReceiverSelector) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *ReceiverSpec) DeepCopyInto(out *ReceiverSpec) { *out = *in @@ -1133,6 +1404,11 @@ func (in *ReceiverSpec) DeepCopyInto(out *ReceiverSpec) { *out = new(PushoverReceiver) (*in).DeepCopyInto(*out) } + if in.Feishu != nil { + in, out := &in.Feishu, &out.Feishu + *out = new(FeishuReceiver) + (*in).DeepCopyInto(*out) + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ReceiverSpec. @@ -1190,6 +1466,106 @@ func (in *ReceiversSpec) DeepCopy() *ReceiversSpec { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Router) DeepCopyInto(out *Router) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + out.Status = in.Status +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Router. +func (in *Router) DeepCopy() *Router { + if in == nil { + return nil + } + out := new(Router) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *Router) 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 *RouterList) DeepCopyInto(out *RouterList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]Router, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RouterList. +func (in *RouterList) DeepCopy() *RouterList { + if in == nil { + return nil + } + out := new(RouterList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *RouterList) 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 *RouterSpec) DeepCopyInto(out *RouterSpec) { + *out = *in + if in.Enabled != nil { + in, out := &in.Enabled, &out.Enabled + *out = new(bool) + **out = **in + } + if in.AlertSelector != nil { + in, out := &in.AlertSelector, &out.AlertSelector + *out = new(metav1.LabelSelector) + (*in).DeepCopyInto(*out) + } + in.Receivers.DeepCopyInto(&out.Receivers) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RouterSpec. +func (in *RouterSpec) DeepCopy() *RouterSpec { + if in == nil { + return nil + } + out := new(RouterSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *RouterStatus) DeepCopyInto(out *RouterStatus) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RouterStatus. +func (in *RouterStatus) DeepCopy() *RouterStatus { + if in == nil { + return nil + } + out := new(RouterStatus) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *SecretKeySelector) DeepCopyInto(out *SecretKeySelector) { *out = *in @@ -1255,6 +1631,114 @@ func (in *Sidecar) DeepCopy() *Sidecar { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Silence) DeepCopyInto(out *Silence) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + out.Status = in.Status +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Silence. +func (in *Silence) DeepCopy() *Silence { + if in == nil { + return nil + } + out := new(Silence) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *Silence) 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 *SilenceList) DeepCopyInto(out *SilenceList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]Silence, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SilenceList. +func (in *SilenceList) DeepCopy() *SilenceList { + if in == nil { + return nil + } + out := new(SilenceList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *SilenceList) 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 *SilenceSpec) DeepCopyInto(out *SilenceSpec) { + *out = *in + if in.Enabled != nil { + in, out := &in.Enabled, &out.Enabled + *out = new(bool) + **out = **in + } + if in.Matcher != nil { + in, out := &in.Matcher, &out.Matcher + *out = new(metav1.LabelSelector) + (*in).DeepCopyInto(*out) + } + if in.StartsAt != nil { + in, out := &in.StartsAt, &out.StartsAt + *out = (*in).DeepCopy() + } + if in.Duration != nil { + in, out := &in.Duration, &out.Duration + *out = new(metav1.Duration) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SilenceSpec. +func (in *SilenceSpec) DeepCopy() *SilenceSpec { + if in == nil { + return nil + } + out := new(SilenceSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *SilenceStatus) DeepCopyInto(out *SilenceStatus) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SilenceStatus. +func (in *SilenceStatus) DeepCopy() *SilenceStatus { + if in == nil { + return nil + } + out := new(SilenceStatus) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *SlackConfig) DeepCopyInto(out *SlackConfig) { *out = *in @@ -1330,6 +1814,11 @@ func (in *SlackReceiver) DeepCopyInto(out *SlackReceiver) { *out = new(string) **out = **in } + if in.TmplText != nil { + in, out := &in.TmplText, &out.TmplText + *out = new(ConfigmapKeySelector) + **out = **in + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SlackReceiver. @@ -1410,6 +1899,11 @@ func (in *SmsReceiver) DeepCopyInto(out *SmsReceiver) { *out = new(string) **out = **in } + if in.TmplText != nil { + in, out := &in.TmplText, &out.TmplText + *out = new(ConfigmapKeySelector) + **out = **in + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SmsReceiver. @@ -1447,6 +1941,38 @@ func (in *TLSConfig) DeepCopy() *TLSConfig { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Template) DeepCopyInto(out *Template) { + *out = *in + if in.Text != nil { + in, out := &in.Text, &out.Text + *out = new(ConfigmapKeySelector) + **out = **in + } + out.ReloadCycle = in.ReloadCycle + if in.LanguagePack != nil { + in, out := &in.LanguagePack, &out.LanguagePack + *out = make([]*ConfigmapKeySelector, len(*in)) + for i := range *in { + if (*in)[i] != nil { + in, out := &(*in)[i], &(*out)[i] + *out = new(ConfigmapKeySelector) + **out = **in + } + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Template. +func (in *Template) DeepCopy() *Template { + if in == nil { + return nil + } + out := new(Template) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *TencentSMS) DeepCopyInto(out *TencentSMS) { *out = *in @@ -1587,6 +2113,11 @@ func (in *WebhookReceiver) DeepCopyInto(out *WebhookReceiver) { *out = new(string) **out = **in } + if in.TmplText != nil { + in, out := &in.TmplText, &out.TmplText + *out = new(ConfigmapKeySelector) + **out = **in + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new WebhookReceiver. @@ -1689,6 +2220,11 @@ func (in *WechatReceiver) DeepCopyInto(out *WechatReceiver) { *out = new(string) **out = **in } + if in.TmplText != nil { + in, out := &in.TmplText, &out.TmplText + *out = new(ConfigmapKeySelector) + **out = **in + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new WechatReceiver. diff --git a/staging/src/kubesphere.io/api/types/v1beta1/federatednotificationconfig_types.go b/staging/src/kubesphere.io/api/types/v1beta1/federatednotificationconfig_types.go index f7823a918..6efeb9fc4 100644 --- a/staging/src/kubesphere.io/api/types/v1beta1/federatednotificationconfig_types.go +++ b/staging/src/kubesphere.io/api/types/v1beta1/federatednotificationconfig_types.go @@ -62,3 +62,5 @@ type FederatedNotificationConfigList struct { metav1.ListMeta `json:"metadata,omitempty"` Items []FederatedNotificationConfig `json:"items"` } + +func (_ *FederatedNotificationConfig) Hub() {} diff --git a/staging/src/kubesphere.io/api/types/v1beta1/federatednotificationreceiver_types.go b/staging/src/kubesphere.io/api/types/v1beta1/federatednotificationreceiver_types.go index 6c2d56c34..8cab56ec4 100644 --- a/staging/src/kubesphere.io/api/types/v1beta1/federatednotificationreceiver_types.go +++ b/staging/src/kubesphere.io/api/types/v1beta1/federatednotificationreceiver_types.go @@ -61,3 +61,5 @@ type FederatedNotificationReceiverList struct { metav1.ListMeta `json:"metadata,omitempty"` Items []FederatedNotificationReceiver `json:"items"` } + +func (_ *FederatedNotificationReceiver) Hub() {} diff --git a/staging/src/kubesphere.io/api/types/v1beta2/federatednotificationconfig_types.go b/staging/src/kubesphere.io/api/types/v1beta2/federatednotificationconfig_types.go new file mode 100644 index 000000000..e4a539151 --- /dev/null +++ b/staging/src/kubesphere.io/api/types/v1beta2/federatednotificationconfig_types.go @@ -0,0 +1,184 @@ +/* +Copyright 2020 KubeSphere Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1beta2 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "kubesphere.io/api/notification/v2beta1" + "kubesphere.io/api/notification/v2beta2" + "kubesphere.io/api/types/v1beta1" + "sigs.k8s.io/controller-runtime/pkg/conversion" +) + +const ( + ResourcePluralFederatedNotificationConfig = "federatednotificationconfigs" + ResourceSingularFederatedNotificationConfig = "federatednotificationconfig" + FederatedNotificationConfigKind = "FederatedNotificationConfig" +) + +// +genclient:nonNamespaced +// +k8s:deepcopy-gen=true +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object +// +k8s:openapi-gen=true +// +kubebuilder:resource:scope=Cluster +// +kubebuilder:subresource:status +// +kubebuilder:storageversion +type FederatedNotificationConfig struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + Spec FederatedNotificationConfigSpec `json:"spec"` + + Status *GenericFederatedStatus `json:"status,omitempty"` +} + +type FederatedNotificationConfigSpec struct { + Template NotificationConfigTemplate `json:"template"` + Placement GenericPlacementFields `json:"placement"` + Overrides []GenericOverrideItem `json:"overrides,omitempty"` +} + +type NotificationConfigTemplate struct { + // +kubebuilder:pruning:PreserveUnknownFields + metav1.ObjectMeta `json:"metadata,omitempty"` + Spec v2beta2.ConfigSpec `json:"spec,omitempty"` +} + +// +k8s:deepcopy-gen=true +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// FederatedNotificationConfigList contains a list of federatednotificationconfiglists +type FederatedNotificationConfigList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []FederatedNotificationConfig `json:"items"` +} + +// ConvertTo converts this Config to the Hub version (v1beta1). +func (src *FederatedNotificationConfig) ConvertTo(dstRaw conversion.Hub) error { + + dst := dstRaw.(*v1beta1.FederatedNotificationConfig) + dst.ObjectMeta = src.ObjectMeta + + srcConfig := v2beta2.Config{ + Spec: src.Spec.Template.Spec, + } + dstConfig := &v2beta1.Config{} + if err := srcConfig.ConvertTo(dstConfig); err != nil { + return err + } + + dst.Spec = v1beta1.FederatedNotificationConfigSpec{ + Template: v1beta1.NotificationConfigTemplate{ + Spec: dstConfig.Spec, + }, + Placement: convertPlacementTo(src.Spec.Placement), + Overrides: convertOverridesTo(src.Spec.Overrides), + } + + return nil +} + +// ConvertFrom converts from the Hub version (v1beta1) to this version. +func (dst *FederatedNotificationConfig) ConvertFrom(srcRaw conversion.Hub) error { + + src := srcRaw.(*v1beta1.FederatedNotificationConfig) + dst.ObjectMeta = src.ObjectMeta + + srcConfig := v2beta1.Config{ + Spec: src.Spec.Template.Spec, + } + dstConfig := &v2beta2.Config{} + if err := dstConfig.ConvertFrom(&srcConfig); err != nil { + return err + } + + dst.Spec = FederatedNotificationConfigSpec{ + Template: NotificationConfigTemplate{ + Spec: dstConfig.Spec, + }, + Placement: convertPlacementFrom(src.Spec.Placement), + Overrides: convertOverridesFrom(src.Spec.Overrides), + } + + return nil +} + +func convertPlacementTo(placement GenericPlacementFields) v1beta1.GenericPlacementFields { + + var clusters []v1beta1.GenericClusterReference + for _, cluster := range placement.Clusters { + clusters = append(clusters, v1beta1.GenericClusterReference{ + Name: cluster.Name, + }) + } + + return v1beta1.GenericPlacementFields{ + Clusters: clusters, + ClusterSelector: placement.ClusterSelector, + } +} + +func convertPlacementFrom(placement v1beta1.GenericPlacementFields) GenericPlacementFields { + + var clusters []GenericClusterReference + for _, cluster := range placement.Clusters { + clusters = append(clusters, GenericClusterReference{ + Name: cluster.Name, + }) + } + + return GenericPlacementFields{ + Clusters: clusters, + ClusterSelector: placement.ClusterSelector, + } +} + +func convertOverridesTo(src []GenericOverrideItem) []v1beta1.GenericOverrideItem { + + var dst []v1beta1.GenericOverrideItem + for _, item := range src { + overrideItem := v1beta1.GenericOverrideItem{ClusterName: item.ClusterName} + for _, clusterOverride := range item.ClusterOverrides { + overrideItem.ClusterOverrides = append(overrideItem.ClusterOverrides, v1beta1.ClusterOverride{ + Op: clusterOverride.Op, + Path: clusterOverride.Path, + Value: clusterOverride.Value, + }) + } + dst = append(dst, overrideItem) + } + + return dst +} + +func convertOverridesFrom(src []v1beta1.GenericOverrideItem) []GenericOverrideItem { + + var dst []GenericOverrideItem + for _, item := range src { + overrideItem := GenericOverrideItem{ClusterName: item.ClusterName} + for _, clusterOverride := range item.ClusterOverrides { + overrideItem.ClusterOverrides = append(overrideItem.ClusterOverrides, ClusterOverride{ + Op: clusterOverride.Op, + Path: clusterOverride.Path, + Value: clusterOverride.Value, + }) + } + dst = append(dst, overrideItem) + } + + return dst +} diff --git a/staging/src/kubesphere.io/api/types/v1beta2/federatednotificationreceiver_types.go b/staging/src/kubesphere.io/api/types/v1beta2/federatednotificationreceiver_types.go new file mode 100644 index 000000000..935a39b30 --- /dev/null +++ b/staging/src/kubesphere.io/api/types/v1beta2/federatednotificationreceiver_types.go @@ -0,0 +1,117 @@ +/* +Copyright 2020 KubeSphere Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1beta2 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "kubesphere.io/api/notification/v2beta1" + "kubesphere.io/api/notification/v2beta2" + "kubesphere.io/api/types/v1beta1" + "sigs.k8s.io/controller-runtime/pkg/conversion" +) + +const ( + ResourcePluralFederatedNotificationReceiver = "federatednotificationreceivers" + ResourceSingularFederatedNotificationReceiver = "federatednotificationreceiver" + FederatedNotificationReceiverKind = "FederatedNotificationReceiver" +) + +// +genclient:nonNamespaced +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object +// +k8s:openapi-gen=true +// +kubebuilder:resource:scope=Cluster +// +kubebuilder:subresource:status +// +kubebuilder:storageversion +type FederatedNotificationReceiver struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + Spec FederatedNotificationReceiverSpec `json:"spec"` + + Status *GenericFederatedStatus `json:"status,omitempty"` +} + +type FederatedNotificationReceiverSpec struct { + Template NotificationReceiverTemplate `json:"template"` + Placement GenericPlacementFields `json:"placement"` + Overrides []GenericOverrideItem `json:"overrides,omitempty"` +} + +type NotificationReceiverTemplate struct { + // +kubebuilder:pruning:PreserveUnknownFields + metav1.ObjectMeta `json:"metadata,omitempty"` + Spec v2beta2.ReceiverSpec `json:"spec,omitempty"` +} + +// +k8s:deepcopy-gen=true +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// FederatedNotificationReceiverList contains a list of federatednotificationreceiverlists +type FederatedNotificationReceiverList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []FederatedNotificationReceiver `json:"items"` +} + +// ConvertTo converts this Config to the Hub version (v1beta1). +func (src *FederatedNotificationReceiver) ConvertTo(dstRaw conversion.Hub) error { + + dst := dstRaw.(*v1beta1.FederatedNotificationReceiver) + dst.ObjectMeta = src.ObjectMeta + + srcReceiver := v2beta2.Receiver{ + Spec: src.Spec.Template.Spec, + } + dstReceiver := &v2beta1.Receiver{} + if err := srcReceiver.ConvertTo(dstReceiver); err != nil { + return err + } + + dst.Spec = v1beta1.FederatedNotificationReceiverSpec{ + Template: v1beta1.NotificationReceiverTemplate{ + Spec: dstReceiver.Spec, + }, + Placement: convertPlacementTo(src.Spec.Placement), + Overrides: convertOverridesTo(src.Spec.Overrides), + } + + return nil +} + +// ConvertFrom converts from the Hub version (v1beta1) to this version. +func (dst *FederatedNotificationReceiver) ConvertFrom(srcRaw conversion.Hub) error { + + src := srcRaw.(*v1beta1.FederatedNotificationReceiver) + dst.ObjectMeta = src.ObjectMeta + + srcReceiver := v2beta1.Receiver{ + Spec: src.Spec.Template.Spec, + } + dstReceiver := &v2beta2.Receiver{} + if err := dstReceiver.ConvertFrom(&srcReceiver); err != nil { + return err + } + + dst.Spec = FederatedNotificationReceiverSpec{ + Template: NotificationReceiverTemplate{ + Spec: dstReceiver.Spec, + }, + Placement: convertPlacementFrom(src.Spec.Placement), + Overrides: convertOverridesFrom(src.Spec.Overrides), + } + + return nil +} diff --git a/staging/src/kubesphere.io/api/types/v1beta2/federatednotificationrouter_types.go b/staging/src/kubesphere.io/api/types/v1beta2/federatednotificationrouter_types.go new file mode 100644 index 000000000..eb37f457f --- /dev/null +++ b/staging/src/kubesphere.io/api/types/v1beta2/federatednotificationrouter_types.go @@ -0,0 +1,64 @@ +/* +Copyright 2020 KubeSphere Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1beta2 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "kubesphere.io/api/notification/v2beta2" +) + +const ( + ResourcePluralFederatedNotificationRouter = "federatednotificationrouters" + ResourceSingularFederatedNotificationRouter = "federatednotificationrouter" + FederatedNotificationRouterKind = "FederatedNotificationRouter" +) + +// +genclient:nonNamespaced +// +k8s:deepcopy-gen=true +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object +// +k8s:openapi-gen=true +// +kubebuilder:resource:scope=Cluster +// +kubebuilder:subresource:status +type FederatedNotificationRouter struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + Spec FederatedNotificationRouterSpec `json:"spec"` + + Status *GenericFederatedStatus `json:"status,omitempty"` +} + +type FederatedNotificationRouterSpec struct { + Template NotificationRouterTemplate `json:"template"` + Placement GenericPlacementFields `json:"placement"` + Overrides []GenericOverrideItem `json:"overrides,omitempty"` +} + +type NotificationRouterTemplate struct { + // +kubebuilder:pruning:PreserveUnknownFields + metav1.ObjectMeta `json:"metadata,omitempty"` + Spec v2beta2.RouterSpec `json:"spec,omitempty"` +} + +// +k8s:deepcopy-gen=true +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// FederatedNotificationRouterList contains a list of federatednotificationrouterlists +type FederatedNotificationRouterList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []FederatedNotificationRouter `json:"items"` +} diff --git a/staging/src/kubesphere.io/api/types/v1beta2/federatednotificationsilence_types.go b/staging/src/kubesphere.io/api/types/v1beta2/federatednotificationsilence_types.go new file mode 100644 index 000000000..ffc79899a --- /dev/null +++ b/staging/src/kubesphere.io/api/types/v1beta2/federatednotificationsilence_types.go @@ -0,0 +1,64 @@ +/* +Copyright 2020 KubeSphere Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1beta2 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "kubesphere.io/api/notification/v2beta2" +) + +const ( + ResourcePluralFederatedNotificationSilence = "federatednotificationsilences" + ResourceSingularFederatedNotificationSilence = "federatednotificationsilence" + FederatedNotificationSilenceKind = "FederatedNotificationSilence" +) + +// +genclient:nonNamespaced +// +k8s:deepcopy-gen=true +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object +// +k8s:openapi-gen=true +// +kubebuilder:resource:scope=Cluster +// +kubebuilder:subresource:status +type FederatedNotificationSilence struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + Spec FederatedNotificationSilenceSpec `json:"spec"` + + Status *GenericFederatedStatus `json:"status,omitempty"` +} + +type FederatedNotificationSilenceSpec struct { + Template NotificationSilenceTemplate `json:"template"` + Placement GenericPlacementFields `json:"placement"` + Overrides []GenericOverrideItem `json:"overrides,omitempty"` +} + +type NotificationSilenceTemplate struct { + // +kubebuilder:pruning:PreserveUnknownFields + metav1.ObjectMeta `json:"metadata,omitempty"` + Spec v2beta2.SilenceSpec `json:"spec,omitempty"` +} + +// +k8s:deepcopy-gen=true +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// FederatedNotificationSilenceList contains a list of federatednotificationsilencelists +type FederatedNotificationSilenceList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []FederatedNotificationSilence `json:"items"` +} diff --git a/staging/src/kubesphere.io/api/types/v1beta2/register.go b/staging/src/kubesphere.io/api/types/v1beta2/register.go new file mode 100644 index 000000000..932822179 --- /dev/null +++ b/staging/src/kubesphere.io/api/types/v1beta2/register.go @@ -0,0 +1,57 @@ +/* +Copyright 2019 The KubeSphere Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// NOTE: Boilerplate only. Ignore this file. + +// +k8s:openapi-gen=true +// +k8s:deepcopy-gen=package,register +// +kubebuilder:object:generate=true +// +groupName=types.kubefed.io +package v1beta2 + +import ( + "k8s.io/apimachinery/pkg/runtime/schema" + "sigs.k8s.io/controller-runtime/pkg/scheme" +) + +var ( + // SchemeGroupVersion is group version used to register these objects + SchemeGroupVersion = schema.GroupVersion{Group: "types.kubefed.io", Version: "v1beta2"} + + // SchemeBuilder is used to add go types to the GroupVersionKind scheme + SchemeBuilder = &scheme.Builder{GroupVersion: SchemeGroupVersion} + + // AddToScheme is required by pkg/client/... + AddToScheme = SchemeBuilder.AddToScheme +) + +// Resource is required by pkg/client/listers/... +func Resource(resource string) schema.GroupResource { + return SchemeGroupVersion.WithResource(resource).GroupResource() +} + +func init() { + SchemeBuilder.Register( + &FederatedNotificationConfig{}, + &FederatedNotificationConfigList{}, + &FederatedNotificationReceiver{}, + &FederatedNotificationReceiverList{}, + &FederatedNotificationRouter{}, + &FederatedNotificationRouterList{}, + &FederatedNotificationSilence{}, + &FederatedNotificationSilenceList{}, + ) +} diff --git a/staging/src/kubesphere.io/api/types/v1beta2/types.go b/staging/src/kubesphere.io/api/types/v1beta2/types.go new file mode 100644 index 000000000..454b17ec8 --- /dev/null +++ b/staging/src/kubesphere.io/api/types/v1beta2/types.go @@ -0,0 +1,108 @@ +/* + + Copyright 2020 The KubeSphere Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +*/ + +package v1beta2 + +import ( + v1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" +) + +type GenericClusterReference struct { + Name string `json:"name"` +} + +type GenericPlacementFields struct { + Clusters []GenericClusterReference `json:"clusters,omitempty"` + ClusterSelector *metav1.LabelSelector `json:"clusterSelector,omitempty"` +} +type GenericPlacementSpec struct { + Placement GenericPlacementFields `json:"placement,omitempty"` +} + +type GenericPlacement struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec GenericPlacementSpec `json:"spec,omitempty"` +} + +type ClusterOverride struct { + Op string `json:"op,omitempty"` + Path string `json:"path"` + // +kubebuilder:pruning:PreserveUnknownFields + Value runtime.RawExtension `json:"value,omitempty"` +} + +type GenericOverrideItem struct { + ClusterName string `json:"clusterName"` + ClusterOverrides []ClusterOverride `json:"clusterOverrides,omitempty"` +} + +type GenericOverrideSpec struct { + Overrides []GenericOverrideItem `json:"overrides,omitempty"` +} + +type GenericOverride struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec *GenericOverrideSpec `json:"spec,omitempty"` +} + +type ConditionType string + +type AggregateReason string + +type PropagationStatus string + +type GenericClusterStatus struct { + Name string `json:"name"` + Status PropagationStatus `json:"status,omitempty"` +} + +type GenericCondition struct { + // Type of cluster condition + Type ConditionType `json:"type"` + // Status of the condition, one of True, False, Unknown. + Status v1.ConditionStatus `json:"status"` + // Last time reconciliation resulted in an error or the last time a + // change was propagated to member clusters. + // +optional + LastUpdateTime string `json:"lastUpdateTime,omitempty"` + // Last time the condition transit from one status to another. + // +optional + LastTransitionTime string `json:"lastTransitionTime,omitempty"` + // (brief) reason for the condition's last transition. + // +optional + Reason AggregateReason `json:"reason,omitempty"` +} + +type GenericFederatedStatus struct { + ObservedGeneration int64 `json:"observedGeneration,omitempty"` + Conditions []*GenericCondition `json:"conditions,omitempty"` + Clusters []GenericClusterStatus `json:"clusters,omitempty"` +} + +type GenericFederatedResource struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Status *GenericFederatedStatus `json:"status,omitempty"` +} diff --git a/staging/src/kubesphere.io/api/types/v1beta2/zz_generated.deepcopy.go b/staging/src/kubesphere.io/api/types/v1beta2/zz_generated.deepcopy.go new file mode 100644 index 000000000..d3f869256 --- /dev/null +++ b/staging/src/kubesphere.io/api/types/v1beta2/zz_generated.deepcopy.go @@ -0,0 +1,681 @@ +// +build !ignore_autogenerated + +/* +Copyright 2020 The KubeSphere Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by controller-gen. DO NOT EDIT. + +package v1beta2 + +import ( + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" +) + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ClusterOverride) DeepCopyInto(out *ClusterOverride) { + *out = *in + in.Value.DeepCopyInto(&out.Value) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClusterOverride. +func (in *ClusterOverride) DeepCopy() *ClusterOverride { + if in == nil { + return nil + } + out := new(ClusterOverride) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *FederatedNotificationConfig) DeepCopyInto(out *FederatedNotificationConfig) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + if in.Status != nil { + in, out := &in.Status, &out.Status + *out = new(GenericFederatedStatus) + (*in).DeepCopyInto(*out) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FederatedNotificationConfig. +func (in *FederatedNotificationConfig) DeepCopy() *FederatedNotificationConfig { + if in == nil { + return nil + } + out := new(FederatedNotificationConfig) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *FederatedNotificationConfig) 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 *FederatedNotificationConfigList) DeepCopyInto(out *FederatedNotificationConfigList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]FederatedNotificationConfig, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FederatedNotificationConfigList. +func (in *FederatedNotificationConfigList) DeepCopy() *FederatedNotificationConfigList { + if in == nil { + return nil + } + out := new(FederatedNotificationConfigList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *FederatedNotificationConfigList) 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 *FederatedNotificationConfigSpec) DeepCopyInto(out *FederatedNotificationConfigSpec) { + *out = *in + in.Template.DeepCopyInto(&out.Template) + in.Placement.DeepCopyInto(&out.Placement) + if in.Overrides != nil { + in, out := &in.Overrides, &out.Overrides + *out = make([]GenericOverrideItem, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FederatedNotificationConfigSpec. +func (in *FederatedNotificationConfigSpec) DeepCopy() *FederatedNotificationConfigSpec { + if in == nil { + return nil + } + out := new(FederatedNotificationConfigSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *FederatedNotificationReceiver) DeepCopyInto(out *FederatedNotificationReceiver) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + if in.Status != nil { + in, out := &in.Status, &out.Status + *out = new(GenericFederatedStatus) + (*in).DeepCopyInto(*out) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FederatedNotificationReceiver. +func (in *FederatedNotificationReceiver) DeepCopy() *FederatedNotificationReceiver { + if in == nil { + return nil + } + out := new(FederatedNotificationReceiver) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *FederatedNotificationReceiver) 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 *FederatedNotificationReceiverList) DeepCopyInto(out *FederatedNotificationReceiverList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]FederatedNotificationReceiver, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FederatedNotificationReceiverList. +func (in *FederatedNotificationReceiverList) DeepCopy() *FederatedNotificationReceiverList { + if in == nil { + return nil + } + out := new(FederatedNotificationReceiverList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *FederatedNotificationReceiverList) 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 *FederatedNotificationReceiverSpec) DeepCopyInto(out *FederatedNotificationReceiverSpec) { + *out = *in + in.Template.DeepCopyInto(&out.Template) + in.Placement.DeepCopyInto(&out.Placement) + if in.Overrides != nil { + in, out := &in.Overrides, &out.Overrides + *out = make([]GenericOverrideItem, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FederatedNotificationReceiverSpec. +func (in *FederatedNotificationReceiverSpec) DeepCopy() *FederatedNotificationReceiverSpec { + if in == nil { + return nil + } + out := new(FederatedNotificationReceiverSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *FederatedNotificationRouter) DeepCopyInto(out *FederatedNotificationRouter) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + if in.Status != nil { + in, out := &in.Status, &out.Status + *out = new(GenericFederatedStatus) + (*in).DeepCopyInto(*out) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FederatedNotificationRouter. +func (in *FederatedNotificationRouter) DeepCopy() *FederatedNotificationRouter { + if in == nil { + return nil + } + out := new(FederatedNotificationRouter) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *FederatedNotificationRouter) 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 *FederatedNotificationRouterList) DeepCopyInto(out *FederatedNotificationRouterList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]FederatedNotificationRouter, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FederatedNotificationRouterList. +func (in *FederatedNotificationRouterList) DeepCopy() *FederatedNotificationRouterList { + if in == nil { + return nil + } + out := new(FederatedNotificationRouterList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *FederatedNotificationRouterList) 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 *FederatedNotificationRouterSpec) DeepCopyInto(out *FederatedNotificationRouterSpec) { + *out = *in + in.Template.DeepCopyInto(&out.Template) + in.Placement.DeepCopyInto(&out.Placement) + if in.Overrides != nil { + in, out := &in.Overrides, &out.Overrides + *out = make([]GenericOverrideItem, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FederatedNotificationRouterSpec. +func (in *FederatedNotificationRouterSpec) DeepCopy() *FederatedNotificationRouterSpec { + if in == nil { + return nil + } + out := new(FederatedNotificationRouterSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *FederatedNotificationSilence) DeepCopyInto(out *FederatedNotificationSilence) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + if in.Status != nil { + in, out := &in.Status, &out.Status + *out = new(GenericFederatedStatus) + (*in).DeepCopyInto(*out) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FederatedNotificationSilence. +func (in *FederatedNotificationSilence) DeepCopy() *FederatedNotificationSilence { + if in == nil { + return nil + } + out := new(FederatedNotificationSilence) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *FederatedNotificationSilence) 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 *FederatedNotificationSilenceList) DeepCopyInto(out *FederatedNotificationSilenceList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]FederatedNotificationSilence, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FederatedNotificationSilenceList. +func (in *FederatedNotificationSilenceList) DeepCopy() *FederatedNotificationSilenceList { + if in == nil { + return nil + } + out := new(FederatedNotificationSilenceList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *FederatedNotificationSilenceList) 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 *FederatedNotificationSilenceSpec) DeepCopyInto(out *FederatedNotificationSilenceSpec) { + *out = *in + in.Template.DeepCopyInto(&out.Template) + in.Placement.DeepCopyInto(&out.Placement) + if in.Overrides != nil { + in, out := &in.Overrides, &out.Overrides + *out = make([]GenericOverrideItem, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FederatedNotificationSilenceSpec. +func (in *FederatedNotificationSilenceSpec) DeepCopy() *FederatedNotificationSilenceSpec { + if in == nil { + return nil + } + out := new(FederatedNotificationSilenceSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *GenericClusterReference) DeepCopyInto(out *GenericClusterReference) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GenericClusterReference. +func (in *GenericClusterReference) DeepCopy() *GenericClusterReference { + if in == nil { + return nil + } + out := new(GenericClusterReference) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *GenericClusterStatus) DeepCopyInto(out *GenericClusterStatus) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GenericClusterStatus. +func (in *GenericClusterStatus) DeepCopy() *GenericClusterStatus { + if in == nil { + return nil + } + out := new(GenericClusterStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *GenericCondition) DeepCopyInto(out *GenericCondition) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GenericCondition. +func (in *GenericCondition) DeepCopy() *GenericCondition { + if in == nil { + return nil + } + out := new(GenericCondition) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *GenericFederatedResource) DeepCopyInto(out *GenericFederatedResource) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + if in.Status != nil { + in, out := &in.Status, &out.Status + *out = new(GenericFederatedStatus) + (*in).DeepCopyInto(*out) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GenericFederatedResource. +func (in *GenericFederatedResource) DeepCopy() *GenericFederatedResource { + if in == nil { + return nil + } + out := new(GenericFederatedResource) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *GenericFederatedStatus) DeepCopyInto(out *GenericFederatedStatus) { + *out = *in + if in.Conditions != nil { + in, out := &in.Conditions, &out.Conditions + *out = make([]*GenericCondition, len(*in)) + for i := range *in { + if (*in)[i] != nil { + in, out := &(*in)[i], &(*out)[i] + *out = new(GenericCondition) + **out = **in + } + } + } + if in.Clusters != nil { + in, out := &in.Clusters, &out.Clusters + *out = make([]GenericClusterStatus, len(*in)) + copy(*out, *in) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GenericFederatedStatus. +func (in *GenericFederatedStatus) DeepCopy() *GenericFederatedStatus { + if in == nil { + return nil + } + out := new(GenericFederatedStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *GenericOverride) DeepCopyInto(out *GenericOverride) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + if in.Spec != nil { + in, out := &in.Spec, &out.Spec + *out = new(GenericOverrideSpec) + (*in).DeepCopyInto(*out) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GenericOverride. +func (in *GenericOverride) DeepCopy() *GenericOverride { + if in == nil { + return nil + } + out := new(GenericOverride) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *GenericOverrideItem) DeepCopyInto(out *GenericOverrideItem) { + *out = *in + if in.ClusterOverrides != nil { + in, out := &in.ClusterOverrides, &out.ClusterOverrides + *out = make([]ClusterOverride, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GenericOverrideItem. +func (in *GenericOverrideItem) DeepCopy() *GenericOverrideItem { + if in == nil { + return nil + } + out := new(GenericOverrideItem) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *GenericOverrideSpec) DeepCopyInto(out *GenericOverrideSpec) { + *out = *in + if in.Overrides != nil { + in, out := &in.Overrides, &out.Overrides + *out = make([]GenericOverrideItem, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GenericOverrideSpec. +func (in *GenericOverrideSpec) DeepCopy() *GenericOverrideSpec { + if in == nil { + return nil + } + out := new(GenericOverrideSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *GenericPlacement) DeepCopyInto(out *GenericPlacement) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GenericPlacement. +func (in *GenericPlacement) DeepCopy() *GenericPlacement { + if in == nil { + return nil + } + out := new(GenericPlacement) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *GenericPlacementFields) DeepCopyInto(out *GenericPlacementFields) { + *out = *in + if in.Clusters != nil { + in, out := &in.Clusters, &out.Clusters + *out = make([]GenericClusterReference, len(*in)) + copy(*out, *in) + } + if in.ClusterSelector != nil { + in, out := &in.ClusterSelector, &out.ClusterSelector + *out = new(v1.LabelSelector) + (*in).DeepCopyInto(*out) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GenericPlacementFields. +func (in *GenericPlacementFields) DeepCopy() *GenericPlacementFields { + if in == nil { + return nil + } + out := new(GenericPlacementFields) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *GenericPlacementSpec) DeepCopyInto(out *GenericPlacementSpec) { + *out = *in + in.Placement.DeepCopyInto(&out.Placement) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GenericPlacementSpec. +func (in *GenericPlacementSpec) DeepCopy() *GenericPlacementSpec { + if in == nil { + return nil + } + out := new(GenericPlacementSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *NotificationConfigTemplate) DeepCopyInto(out *NotificationConfigTemplate) { + *out = *in + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NotificationConfigTemplate. +func (in *NotificationConfigTemplate) DeepCopy() *NotificationConfigTemplate { + if in == nil { + return nil + } + out := new(NotificationConfigTemplate) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *NotificationReceiverTemplate) DeepCopyInto(out *NotificationReceiverTemplate) { + *out = *in + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NotificationReceiverTemplate. +func (in *NotificationReceiverTemplate) DeepCopy() *NotificationReceiverTemplate { + if in == nil { + return nil + } + out := new(NotificationReceiverTemplate) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *NotificationRouterTemplate) DeepCopyInto(out *NotificationRouterTemplate) { + *out = *in + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NotificationRouterTemplate. +func (in *NotificationRouterTemplate) DeepCopy() *NotificationRouterTemplate { + if in == nil { + return nil + } + out := new(NotificationRouterTemplate) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *NotificationSilenceTemplate) DeepCopyInto(out *NotificationSilenceTemplate) { + *out = *in + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NotificationSilenceTemplate. +func (in *NotificationSilenceTemplate) DeepCopy() *NotificationSilenceTemplate { + if in == nil { + return nil + } + out := new(NotificationSilenceTemplate) + in.DeepCopyInto(out) + return out +} diff --git a/vendor/github.com/robfig/cron/v3/.gitignore b/vendor/github.com/robfig/cron/v3/.gitignore new file mode 100644 index 000000000..00268614f --- /dev/null +++ b/vendor/github.com/robfig/cron/v3/.gitignore @@ -0,0 +1,22 @@ +# Compiled Object files, Static and Dynamic libs (Shared Objects) +*.o +*.a +*.so + +# Folders +_obj +_test + +# Architecture specific extensions/prefixes +*.[568vq] +[568vq].out + +*.cgo1.go +*.cgo2.c +_cgo_defun.c +_cgo_gotypes.go +_cgo_export.* + +_testmain.go + +*.exe diff --git a/vendor/github.com/robfig/cron/v3/.travis.yml b/vendor/github.com/robfig/cron/v3/.travis.yml new file mode 100644 index 000000000..4f2ee4d97 --- /dev/null +++ b/vendor/github.com/robfig/cron/v3/.travis.yml @@ -0,0 +1 @@ +language: go diff --git a/vendor/github.com/robfig/cron/v3/LICENSE b/vendor/github.com/robfig/cron/v3/LICENSE new file mode 100644 index 000000000..3a0f627ff --- /dev/null +++ b/vendor/github.com/robfig/cron/v3/LICENSE @@ -0,0 +1,21 @@ +Copyright (C) 2012 Rob Figueiredo +All Rights Reserved. + +MIT LICENSE + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/vendor/github.com/robfig/cron/v3/README.md b/vendor/github.com/robfig/cron/v3/README.md new file mode 100644 index 000000000..984c537c0 --- /dev/null +++ b/vendor/github.com/robfig/cron/v3/README.md @@ -0,0 +1,125 @@ +[![GoDoc](http://godoc.org/github.com/robfig/cron?status.png)](http://godoc.org/github.com/robfig/cron) +[![Build Status](https://travis-ci.org/robfig/cron.svg?branch=master)](https://travis-ci.org/robfig/cron) + +# cron + +Cron V3 has been released! + +To download the specific tagged release, run: + + go get github.com/robfig/cron/v3@v3.0.0 + +Import it in your program as: + + import "github.com/robfig/cron/v3" + +It requires Go 1.11 or later due to usage of Go Modules. + +Refer to the documentation here: +http://godoc.org/github.com/robfig/cron + +The rest of this document describes the the advances in v3 and a list of +breaking changes for users that wish to upgrade from an earlier version. + +## Upgrading to v3 (June 2019) + +cron v3 is a major upgrade to the library that addresses all outstanding bugs, +feature requests, and rough edges. It is based on a merge of master which +contains various fixes to issues found over the years and the v2 branch which +contains some backwards-incompatible features like the ability to remove cron +jobs. In addition, v3 adds support for Go Modules, cleans up rough edges like +the timezone support, and fixes a number of bugs. + +New features: + +- Support for Go modules. Callers must now import this library as + `github.com/robfig/cron/v3`, instead of `gopkg.in/...` + +- Fixed bugs: + - 0f01e6b parser: fix combining of Dow and Dom (#70) + - dbf3220 adjust times when rolling the clock forward to handle non-existent midnight (#157) + - eeecf15 spec_test.go: ensure an error is returned on 0 increment (#144) + - 70971dc cron.Entries(): update request for snapshot to include a reply channel (#97) + - 1cba5e6 cron: fix: removing a job causes the next scheduled job to run too late (#206) + +- Standard cron spec parsing by default (first field is "minute"), with an easy + way to opt into the seconds field (quartz-compatible). Although, note that the + year field (optional in Quartz) is not supported. + +- Extensible, key/value logging via an interface that complies with + the https://github.com/go-logr/logr project. + +- The new Chain & JobWrapper types allow you to install "interceptors" to add + cross-cutting behavior like the following: + - Recover any panics from jobs + - Delay a job's execution if the previous run hasn't completed yet + - Skip a job's execution if the previous run hasn't completed yet + - Log each job's invocations + - Notification when jobs are completed + +It is backwards incompatible with both v1 and v2. These updates are required: + +- The v1 branch accepted an optional seconds field at the beginning of the cron + spec. This is non-standard and has led to a lot of confusion. The new default + parser conforms to the standard as described by [the Cron wikipedia page]. + + UPDATING: To retain the old behavior, construct your Cron with a custom + parser: + + // Seconds field, required + cron.New(cron.WithSeconds()) + + // Seconds field, optional + cron.New( + cron.WithParser( + cron.SecondOptional | cron.Minute | cron.Hour | cron.Dom | cron.Month | cron.Dow | cron.Descriptor)) + +- The Cron type now accepts functional options on construction rather than the + previous ad-hoc behavior modification mechanisms (setting a field, calling a setter). + + UPDATING: Code that sets Cron.ErrorLogger or calls Cron.SetLocation must be + updated to provide those values on construction. + +- CRON_TZ is now the recommended way to specify the timezone of a single + schedule, which is sanctioned by the specification. The legacy "TZ=" prefix + will continue to be supported since it is unambiguous and easy to do so. + + UPDATING: No update is required. + +- By default, cron will no longer recover panics in jobs that it runs. + Recovering can be surprising (see issue #192) and seems to be at odds with + typical behavior of libraries. Relatedly, the `cron.WithPanicLogger` option + has been removed to accommodate the more general JobWrapper type. + + UPDATING: To opt into panic recovery and configure the panic logger: + + cron.New(cron.WithChain( + cron.Recover(logger), // or use cron.DefaultLogger + )) + +- In adding support for https://github.com/go-logr/logr, `cron.WithVerboseLogger` was + removed, since it is duplicative with the leveled logging. + + UPDATING: Callers should use `WithLogger` and specify a logger that does not + discard `Info` logs. For convenience, one is provided that wraps `*log.Logger`: + + cron.New( + cron.WithLogger(cron.VerbosePrintfLogger(logger))) + + +### Background - Cron spec format + +There are two cron spec formats in common usage: + +- The "standard" cron format, described on [the Cron wikipedia page] and used by + the cron Linux system utility. + +- The cron format used by [the Quartz Scheduler], commonly used for scheduled + jobs in Java software + +[the Cron wikipedia page]: https://en.wikipedia.org/wiki/Cron +[the Quartz Scheduler]: http://www.quartz-scheduler.org/documentation/quartz-2.3.0/tutorials/tutorial-lesson-06.html + +The original version of this package included an optional "seconds" field, which +made it incompatible with both of these formats. Now, the "standard" format is +the default format accepted, and the Quartz format is opt-in. diff --git a/vendor/github.com/robfig/cron/v3/chain.go b/vendor/github.com/robfig/cron/v3/chain.go new file mode 100644 index 000000000..9565b418e --- /dev/null +++ b/vendor/github.com/robfig/cron/v3/chain.go @@ -0,0 +1,92 @@ +package cron + +import ( + "fmt" + "runtime" + "sync" + "time" +) + +// JobWrapper decorates the given Job with some behavior. +type JobWrapper func(Job) Job + +// Chain is a sequence of JobWrappers that decorates submitted jobs with +// cross-cutting behaviors like logging or synchronization. +type Chain struct { + wrappers []JobWrapper +} + +// NewChain returns a Chain consisting of the given JobWrappers. +func NewChain(c ...JobWrapper) Chain { + return Chain{c} +} + +// Then decorates the given job with all JobWrappers in the chain. +// +// This: +// NewChain(m1, m2, m3).Then(job) +// is equivalent to: +// m1(m2(m3(job))) +func (c Chain) Then(j Job) Job { + for i := range c.wrappers { + j = c.wrappers[len(c.wrappers)-i-1](j) + } + return j +} + +// Recover panics in wrapped jobs and log them with the provided logger. +func Recover(logger Logger) JobWrapper { + return func(j Job) Job { + return FuncJob(func() { + defer func() { + if r := recover(); r != nil { + const size = 64 << 10 + buf := make([]byte, size) + buf = buf[:runtime.Stack(buf, false)] + err, ok := r.(error) + if !ok { + err = fmt.Errorf("%v", r) + } + logger.Error(err, "panic", "stack", "...\n"+string(buf)) + } + }() + j.Run() + }) + } +} + +// DelayIfStillRunning serializes jobs, delaying subsequent runs until the +// previous one is complete. Jobs running after a delay of more than a minute +// have the delay logged at Info. +func DelayIfStillRunning(logger Logger) JobWrapper { + return func(j Job) Job { + var mu sync.Mutex + return FuncJob(func() { + start := time.Now() + mu.Lock() + defer mu.Unlock() + if dur := time.Since(start); dur > time.Minute { + logger.Info("delay", "duration", dur) + } + j.Run() + }) + } +} + +// SkipIfStillRunning skips an invocation of the Job if a previous invocation is +// still running. It logs skips to the given logger at Info level. +func SkipIfStillRunning(logger Logger) JobWrapper { + return func(j Job) Job { + var ch = make(chan struct{}, 1) + ch <- struct{}{} + return FuncJob(func() { + select { + case v := <-ch: + j.Run() + ch <- v + default: + logger.Info("skip") + } + }) + } +} diff --git a/vendor/github.com/robfig/cron/v3/constantdelay.go b/vendor/github.com/robfig/cron/v3/constantdelay.go new file mode 100644 index 000000000..cd6e7b1be --- /dev/null +++ b/vendor/github.com/robfig/cron/v3/constantdelay.go @@ -0,0 +1,27 @@ +package cron + +import "time" + +// ConstantDelaySchedule represents a simple recurring duty cycle, e.g. "Every 5 minutes". +// It does not support jobs more frequent than once a second. +type ConstantDelaySchedule struct { + Delay time.Duration +} + +// Every returns a crontab Schedule that activates once every duration. +// Delays of less than a second are not supported (will round up to 1 second). +// Any fields less than a Second are truncated. +func Every(duration time.Duration) ConstantDelaySchedule { + if duration < time.Second { + duration = time.Second + } + return ConstantDelaySchedule{ + Delay: duration - time.Duration(duration.Nanoseconds())%time.Second, + } +} + +// Next returns the next time this should be run. +// This rounds so that the next activation time will be on the second. +func (schedule ConstantDelaySchedule) Next(t time.Time) time.Time { + return t.Add(schedule.Delay - time.Duration(t.Nanosecond())*time.Nanosecond) +} diff --git a/vendor/github.com/robfig/cron/v3/cron.go b/vendor/github.com/robfig/cron/v3/cron.go new file mode 100644 index 000000000..c7e917665 --- /dev/null +++ b/vendor/github.com/robfig/cron/v3/cron.go @@ -0,0 +1,355 @@ +package cron + +import ( + "context" + "sort" + "sync" + "time" +) + +// Cron keeps track of any number of entries, invoking the associated func as +// specified by the schedule. It may be started, stopped, and the entries may +// be inspected while running. +type Cron struct { + entries []*Entry + chain Chain + stop chan struct{} + add chan *Entry + remove chan EntryID + snapshot chan chan []Entry + running bool + logger Logger + runningMu sync.Mutex + location *time.Location + parser ScheduleParser + nextID EntryID + jobWaiter sync.WaitGroup +} + +// ScheduleParser is an interface for schedule spec parsers that return a Schedule +type ScheduleParser interface { + Parse(spec string) (Schedule, error) +} + +// Job is an interface for submitted cron jobs. +type Job interface { + Run() +} + +// Schedule describes a job's duty cycle. +type Schedule interface { + // Next returns the next activation time, later than the given time. + // Next is invoked initially, and then each time the job is run. + Next(time.Time) time.Time +} + +// EntryID identifies an entry within a Cron instance +type EntryID int + +// Entry consists of a schedule and the func to execute on that schedule. +type Entry struct { + // ID is the cron-assigned ID of this entry, which may be used to look up a + // snapshot or remove it. + ID EntryID + + // Schedule on which this job should be run. + Schedule Schedule + + // Next time the job will run, or the zero time if Cron has not been + // started or this entry's schedule is unsatisfiable + Next time.Time + + // Prev is the last time this job was run, or the zero time if never. + Prev time.Time + + // WrappedJob is the thing to run when the Schedule is activated. + WrappedJob Job + + // Job is the thing that was submitted to cron. + // It is kept around so that user code that needs to get at the job later, + // e.g. via Entries() can do so. + Job Job +} + +// Valid returns true if this is not the zero entry. +func (e Entry) Valid() bool { return e.ID != 0 } + +// byTime is a wrapper for sorting the entry array by time +// (with zero time at the end). +type byTime []*Entry + +func (s byTime) Len() int { return len(s) } +func (s byTime) Swap(i, j int) { s[i], s[j] = s[j], s[i] } +func (s byTime) Less(i, j int) bool { + // Two zero times should return false. + // Otherwise, zero is "greater" than any other time. + // (To sort it at the end of the list.) + if s[i].Next.IsZero() { + return false + } + if s[j].Next.IsZero() { + return true + } + return s[i].Next.Before(s[j].Next) +} + +// New returns a new Cron job runner, modified by the given options. +// +// Available Settings +// +// Time Zone +// Description: The time zone in which schedules are interpreted +// Default: time.Local +// +// Parser +// Description: Parser converts cron spec strings into cron.Schedules. +// Default: Accepts this spec: https://en.wikipedia.org/wiki/Cron +// +// Chain +// Description: Wrap submitted jobs to customize behavior. +// Default: A chain that recovers panics and logs them to stderr. +// +// See "cron.With*" to modify the default behavior. +func New(opts ...Option) *Cron { + c := &Cron{ + entries: nil, + chain: NewChain(), + add: make(chan *Entry), + stop: make(chan struct{}), + snapshot: make(chan chan []Entry), + remove: make(chan EntryID), + running: false, + runningMu: sync.Mutex{}, + logger: DefaultLogger, + location: time.Local, + parser: standardParser, + } + for _, opt := range opts { + opt(c) + } + return c +} + +// FuncJob is a wrapper that turns a func() into a cron.Job +type FuncJob func() + +func (f FuncJob) Run() { f() } + +// AddFunc adds a func to the Cron to be run on the given schedule. +// The spec is parsed using the time zone of this Cron instance as the default. +// An opaque ID is returned that can be used to later remove it. +func (c *Cron) AddFunc(spec string, cmd func()) (EntryID, error) { + return c.AddJob(spec, FuncJob(cmd)) +} + +// AddJob adds a Job to the Cron to be run on the given schedule. +// The spec is parsed using the time zone of this Cron instance as the default. +// An opaque ID is returned that can be used to later remove it. +func (c *Cron) AddJob(spec string, cmd Job) (EntryID, error) { + schedule, err := c.parser.Parse(spec) + if err != nil { + return 0, err + } + return c.Schedule(schedule, cmd), nil +} + +// Schedule adds a Job to the Cron to be run on the given schedule. +// The job is wrapped with the configured Chain. +func (c *Cron) Schedule(schedule Schedule, cmd Job) EntryID { + c.runningMu.Lock() + defer c.runningMu.Unlock() + c.nextID++ + entry := &Entry{ + ID: c.nextID, + Schedule: schedule, + WrappedJob: c.chain.Then(cmd), + Job: cmd, + } + if !c.running { + c.entries = append(c.entries, entry) + } else { + c.add <- entry + } + return entry.ID +} + +// Entries returns a snapshot of the cron entries. +func (c *Cron) Entries() []Entry { + c.runningMu.Lock() + defer c.runningMu.Unlock() + if c.running { + replyChan := make(chan []Entry, 1) + c.snapshot <- replyChan + return <-replyChan + } + return c.entrySnapshot() +} + +// Location gets the time zone location +func (c *Cron) Location() *time.Location { + return c.location +} + +// Entry returns a snapshot of the given entry, or nil if it couldn't be found. +func (c *Cron) Entry(id EntryID) Entry { + for _, entry := range c.Entries() { + if id == entry.ID { + return entry + } + } + return Entry{} +} + +// Remove an entry from being run in the future. +func (c *Cron) Remove(id EntryID) { + c.runningMu.Lock() + defer c.runningMu.Unlock() + if c.running { + c.remove <- id + } else { + c.removeEntry(id) + } +} + +// Start the cron scheduler in its own goroutine, or no-op if already started. +func (c *Cron) Start() { + c.runningMu.Lock() + defer c.runningMu.Unlock() + if c.running { + return + } + c.running = true + go c.run() +} + +// Run the cron scheduler, or no-op if already running. +func (c *Cron) Run() { + c.runningMu.Lock() + if c.running { + c.runningMu.Unlock() + return + } + c.running = true + c.runningMu.Unlock() + c.run() +} + +// run the scheduler.. this is private just due to the need to synchronize +// access to the 'running' state variable. +func (c *Cron) run() { + c.logger.Info("start") + + // Figure out the next activation times for each entry. + now := c.now() + for _, entry := range c.entries { + entry.Next = entry.Schedule.Next(now) + c.logger.Info("schedule", "now", now, "entry", entry.ID, "next", entry.Next) + } + + for { + // Determine the next entry to run. + sort.Sort(byTime(c.entries)) + + var timer *time.Timer + if len(c.entries) == 0 || c.entries[0].Next.IsZero() { + // If there are no entries yet, just sleep - it still handles new entries + // and stop requests. + timer = time.NewTimer(100000 * time.Hour) + } else { + timer = time.NewTimer(c.entries[0].Next.Sub(now)) + } + + for { + select { + case now = <-timer.C: + now = now.In(c.location) + c.logger.Info("wake", "now", now) + + // Run every entry whose next time was less than now + for _, e := range c.entries { + if e.Next.After(now) || e.Next.IsZero() { + break + } + c.startJob(e.WrappedJob) + e.Prev = e.Next + e.Next = e.Schedule.Next(now) + c.logger.Info("run", "now", now, "entry", e.ID, "next", e.Next) + } + + case newEntry := <-c.add: + timer.Stop() + now = c.now() + newEntry.Next = newEntry.Schedule.Next(now) + c.entries = append(c.entries, newEntry) + c.logger.Info("added", "now", now, "entry", newEntry.ID, "next", newEntry.Next) + + case replyChan := <-c.snapshot: + replyChan <- c.entrySnapshot() + continue + + case <-c.stop: + timer.Stop() + c.logger.Info("stop") + return + + case id := <-c.remove: + timer.Stop() + now = c.now() + c.removeEntry(id) + c.logger.Info("removed", "entry", id) + } + + break + } + } +} + +// startJob runs the given job in a new goroutine. +func (c *Cron) startJob(j Job) { + c.jobWaiter.Add(1) + go func() { + defer c.jobWaiter.Done() + j.Run() + }() +} + +// now returns current time in c location +func (c *Cron) now() time.Time { + return time.Now().In(c.location) +} + +// Stop stops the cron scheduler if it is running; otherwise it does nothing. +// A context is returned so the caller can wait for running jobs to complete. +func (c *Cron) Stop() context.Context { + c.runningMu.Lock() + defer c.runningMu.Unlock() + if c.running { + c.stop <- struct{}{} + c.running = false + } + ctx, cancel := context.WithCancel(context.Background()) + go func() { + c.jobWaiter.Wait() + cancel() + }() + return ctx +} + +// entrySnapshot returns a copy of the current cron entry list. +func (c *Cron) entrySnapshot() []Entry { + var entries = make([]Entry, len(c.entries)) + for i, e := range c.entries { + entries[i] = *e + } + return entries +} + +func (c *Cron) removeEntry(id EntryID) { + var entries []*Entry + for _, e := range c.entries { + if e.ID != id { + entries = append(entries, e) + } + } + c.entries = entries +} diff --git a/vendor/github.com/robfig/cron/v3/doc.go b/vendor/github.com/robfig/cron/v3/doc.go new file mode 100644 index 000000000..fa5d08b4d --- /dev/null +++ b/vendor/github.com/robfig/cron/v3/doc.go @@ -0,0 +1,231 @@ +/* +Package cron implements a cron spec parser and job runner. + +Installation + +To download the specific tagged release, run: + + go get github.com/robfig/cron/v3@v3.0.0 + +Import it in your program as: + + import "github.com/robfig/cron/v3" + +It requires Go 1.11 or later due to usage of Go Modules. + +Usage + +Callers may register Funcs to be invoked on a given schedule. Cron will run +them in their own goroutines. + + c := cron.New() + c.AddFunc("30 * * * *", func() { fmt.Println("Every hour on the half hour") }) + c.AddFunc("30 3-6,20-23 * * *", func() { fmt.Println(".. in the range 3-6am, 8-11pm") }) + c.AddFunc("CRON_TZ=Asia/Tokyo 30 04 * * *", func() { fmt.Println("Runs at 04:30 Tokyo time every day") }) + c.AddFunc("@hourly", func() { fmt.Println("Every hour, starting an hour from now") }) + c.AddFunc("@every 1h30m", func() { fmt.Println("Every hour thirty, starting an hour thirty from now") }) + c.Start() + .. + // Funcs are invoked in their own goroutine, asynchronously. + ... + // Funcs may also be added to a running Cron + c.AddFunc("@daily", func() { fmt.Println("Every day") }) + .. + // Inspect the cron job entries' next and previous run times. + inspect(c.Entries()) + .. + c.Stop() // Stop the scheduler (does not stop any jobs already running). + +CRON Expression Format + +A cron expression represents a set of times, using 5 space-separated fields. + + Field name | Mandatory? | Allowed values | Allowed special characters + ---------- | ---------- | -------------- | -------------------------- + Minutes | Yes | 0-59 | * / , - + Hours | Yes | 0-23 | * / , - + Day of month | Yes | 1-31 | * / , - ? + Month | Yes | 1-12 or JAN-DEC | * / , - + Day of week | Yes | 0-6 or SUN-SAT | * / , - ? + +Month and Day-of-week field values are case insensitive. "SUN", "Sun", and +"sun" are equally accepted. + +The specific interpretation of the format is based on the Cron Wikipedia page: +https://en.wikipedia.org/wiki/Cron + +Alternative Formats + +Alternative Cron expression formats support other fields like seconds. You can +implement that by creating a custom Parser as follows. + + cron.New( + cron.WithParser( + cron.NewParser( + cron.SecondOptional | cron.Minute | cron.Hour | cron.Dom | cron.Month | cron.Dow | cron.Descriptor))) + +Since adding Seconds is the most common modification to the standard cron spec, +cron provides a builtin function to do that, which is equivalent to the custom +parser you saw earlier, except that its seconds field is REQUIRED: + + cron.New(cron.WithSeconds()) + +That emulates Quartz, the most popular alternative Cron schedule format: +http://www.quartz-scheduler.org/documentation/quartz-2.x/tutorials/crontrigger.html + +Special Characters + +Asterisk ( * ) + +The asterisk indicates that the cron expression will match for all values of the +field; e.g., using an asterisk in the 5th field (month) would indicate every +month. + +Slash ( / ) + +Slashes are used to describe increments of ranges. For example 3-59/15 in the +1st field (minutes) would indicate the 3rd minute of the hour and every 15 +minutes thereafter. The form "*\/..." is equivalent to the form "first-last/...", +that is, an increment over the largest possible range of the field. The form +"N/..." is accepted as meaning "N-MAX/...", that is, starting at N, use the +increment until the end of that specific range. It does not wrap around. + +Comma ( , ) + +Commas are used to separate items of a list. For example, using "MON,WED,FRI" in +the 5th field (day of week) would mean Mondays, Wednesdays and Fridays. + +Hyphen ( - ) + +Hyphens are used to define ranges. For example, 9-17 would indicate every +hour between 9am and 5pm inclusive. + +Question mark ( ? ) + +Question mark may be used instead of '*' for leaving either day-of-month or +day-of-week blank. + +Predefined schedules + +You may use one of several pre-defined schedules in place of a cron expression. + + Entry | Description | Equivalent To + ----- | ----------- | ------------- + @yearly (or @annually) | Run once a year, midnight, Jan. 1st | 0 0 1 1 * + @monthly | Run once a month, midnight, first of month | 0 0 1 * * + @weekly | Run once a week, midnight between Sat/Sun | 0 0 * * 0 + @daily (or @midnight) | Run once a day, midnight | 0 0 * * * + @hourly | Run once an hour, beginning of hour | 0 * * * * + +Intervals + +You may also schedule a job to execute at fixed intervals, starting at the time it's added +or cron is run. This is supported by formatting the cron spec like this: + + @every + +where "duration" is a string accepted by time.ParseDuration +(http://golang.org/pkg/time/#ParseDuration). + +For example, "@every 1h30m10s" would indicate a schedule that activates after +1 hour, 30 minutes, 10 seconds, and then every interval after that. + +Note: The interval does not take the job runtime into account. For example, +if a job takes 3 minutes to run, and it is scheduled to run every 5 minutes, +it will have only 2 minutes of idle time between each run. + +Time zones + +By default, all interpretation and scheduling is done in the machine's local +time zone (time.Local). You can specify a different time zone on construction: + + cron.New( + cron.WithLocation(time.UTC)) + +Individual cron schedules may also override the time zone they are to be +interpreted in by providing an additional space-separated field at the beginning +of the cron spec, of the form "CRON_TZ=Asia/Tokyo". + +For example: + + # Runs at 6am in time.Local + cron.New().AddFunc("0 6 * * ?", ...) + + # Runs at 6am in America/New_York + nyc, _ := time.LoadLocation("America/New_York") + c := cron.New(cron.WithLocation(nyc)) + c.AddFunc("0 6 * * ?", ...) + + # Runs at 6am in Asia/Tokyo + cron.New().AddFunc("CRON_TZ=Asia/Tokyo 0 6 * * ?", ...) + + # Runs at 6am in Asia/Tokyo + c := cron.New(cron.WithLocation(nyc)) + c.SetLocation("America/New_York") + c.AddFunc("CRON_TZ=Asia/Tokyo 0 6 * * ?", ...) + +The prefix "TZ=(TIME ZONE)" is also supported for legacy compatibility. + +Be aware that jobs scheduled during daylight-savings leap-ahead transitions will +not be run! + +Job Wrappers + +A Cron runner may be configured with a chain of job wrappers to add +cross-cutting functionality to all submitted jobs. For example, they may be used +to achieve the following effects: + + - Recover any panics from jobs (activated by default) + - Delay a job's execution if the previous run hasn't completed yet + - Skip a job's execution if the previous run hasn't completed yet + - Log each job's invocations + +Install wrappers for all jobs added to a cron using the `cron.WithChain` option: + + cron.New(cron.WithChain( + cron.SkipIfStillRunning(logger), + )) + +Install wrappers for individual jobs by explicitly wrapping them: + + job = cron.NewChain( + cron.SkipIfStillRunning(logger), + ).Then(job) + +Thread safety + +Since the Cron service runs concurrently with the calling code, some amount of +care must be taken to ensure proper synchronization. + +All cron methods are designed to be correctly synchronized as long as the caller +ensures that invocations have a clear happens-before ordering between them. + +Logging + +Cron defines a Logger interface that is a subset of the one defined in +github.com/go-logr/logr. It has two logging levels (Info and Error), and +parameters are key/value pairs. This makes it possible for cron logging to plug +into structured logging systems. An adapter, [Verbose]PrintfLogger, is provided +to wrap the standard library *log.Logger. + +For additional insight into Cron operations, verbose logging may be activated +which will record job runs, scheduling decisions, and added or removed jobs. +Activate it with a one-off logger as follows: + + cron.New( + cron.WithLogger( + cron.VerbosePrintfLogger(log.New(os.Stdout, "cron: ", log.LstdFlags)))) + + +Implementation + +Cron entries are stored in an array, sorted by their next activation time. Cron +sleeps until the next job is due to be run. + +Upon waking: + - it runs each entry that is active on that second + - it calculates the next run times for the jobs that were run + - it re-sorts the array of entries by next activation time. + - it goes to sleep until the soonest job. +*/ +package cron diff --git a/vendor/github.com/robfig/cron/v3/go.mod b/vendor/github.com/robfig/cron/v3/go.mod new file mode 100644 index 000000000..8c95bf479 --- /dev/null +++ b/vendor/github.com/robfig/cron/v3/go.mod @@ -0,0 +1,3 @@ +module github.com/robfig/cron/v3 + +go 1.12 diff --git a/vendor/github.com/robfig/cron/v3/logger.go b/vendor/github.com/robfig/cron/v3/logger.go new file mode 100644 index 000000000..b4efcc053 --- /dev/null +++ b/vendor/github.com/robfig/cron/v3/logger.go @@ -0,0 +1,86 @@ +package cron + +import ( + "io/ioutil" + "log" + "os" + "strings" + "time" +) + +// DefaultLogger is used by Cron if none is specified. +var DefaultLogger Logger = PrintfLogger(log.New(os.Stdout, "cron: ", log.LstdFlags)) + +// DiscardLogger can be used by callers to discard all log messages. +var DiscardLogger Logger = PrintfLogger(log.New(ioutil.Discard, "", 0)) + +// Logger is the interface used in this package for logging, so that any backend +// can be plugged in. It is a subset of the github.com/go-logr/logr interface. +type Logger interface { + // Info logs routine messages about cron's operation. + Info(msg string, keysAndValues ...interface{}) + // Error logs an error condition. + Error(err error, msg string, keysAndValues ...interface{}) +} + +// PrintfLogger wraps a Printf-based logger (such as the standard library "log") +// into an implementation of the Logger interface which logs errors only. +func PrintfLogger(l interface{ Printf(string, ...interface{}) }) Logger { + return printfLogger{l, false} +} + +// VerbosePrintfLogger wraps a Printf-based logger (such as the standard library +// "log") into an implementation of the Logger interface which logs everything. +func VerbosePrintfLogger(l interface{ Printf(string, ...interface{}) }) Logger { + return printfLogger{l, true} +} + +type printfLogger struct { + logger interface{ Printf(string, ...interface{}) } + logInfo bool +} + +func (pl printfLogger) Info(msg string, keysAndValues ...interface{}) { + if pl.logInfo { + keysAndValues = formatTimes(keysAndValues) + pl.logger.Printf( + formatString(len(keysAndValues)), + append([]interface{}{msg}, keysAndValues...)...) + } +} + +func (pl printfLogger) Error(err error, msg string, keysAndValues ...interface{}) { + keysAndValues = formatTimes(keysAndValues) + pl.logger.Printf( + formatString(len(keysAndValues)+2), + append([]interface{}{msg, "error", err}, keysAndValues...)...) +} + +// formatString returns a logfmt-like format string for the number of +// key/values. +func formatString(numKeysAndValues int) string { + var sb strings.Builder + sb.WriteString("%s") + if numKeysAndValues > 0 { + sb.WriteString(", ") + } + for i := 0; i < numKeysAndValues/2; i++ { + if i > 0 { + sb.WriteString(", ") + } + sb.WriteString("%v=%v") + } + return sb.String() +} + +// formatTimes formats any time.Time values as RFC3339. +func formatTimes(keysAndValues []interface{}) []interface{} { + var formattedArgs []interface{} + for _, arg := range keysAndValues { + if t, ok := arg.(time.Time); ok { + arg = t.Format(time.RFC3339) + } + formattedArgs = append(formattedArgs, arg) + } + return formattedArgs +} diff --git a/vendor/github.com/robfig/cron/v3/option.go b/vendor/github.com/robfig/cron/v3/option.go new file mode 100644 index 000000000..09e4278e7 --- /dev/null +++ b/vendor/github.com/robfig/cron/v3/option.go @@ -0,0 +1,45 @@ +package cron + +import ( + "time" +) + +// Option represents a modification to the default behavior of a Cron. +type Option func(*Cron) + +// WithLocation overrides the timezone of the cron instance. +func WithLocation(loc *time.Location) Option { + return func(c *Cron) { + c.location = loc + } +} + +// WithSeconds overrides the parser used for interpreting job schedules to +// include a seconds field as the first one. +func WithSeconds() Option { + return WithParser(NewParser( + Second | Minute | Hour | Dom | Month | Dow | Descriptor, + )) +} + +// WithParser overrides the parser used for interpreting job schedules. +func WithParser(p ScheduleParser) Option { + return func(c *Cron) { + c.parser = p + } +} + +// WithChain specifies Job wrappers to apply to all jobs added to this cron. +// Refer to the Chain* functions in this package for provided wrappers. +func WithChain(wrappers ...JobWrapper) Option { + return func(c *Cron) { + c.chain = NewChain(wrappers...) + } +} + +// WithLogger uses the provided logger. +func WithLogger(logger Logger) Option { + return func(c *Cron) { + c.logger = logger + } +} diff --git a/vendor/github.com/robfig/cron/v3/parser.go b/vendor/github.com/robfig/cron/v3/parser.go new file mode 100644 index 000000000..3cf8879f7 --- /dev/null +++ b/vendor/github.com/robfig/cron/v3/parser.go @@ -0,0 +1,434 @@ +package cron + +import ( + "fmt" + "math" + "strconv" + "strings" + "time" +) + +// Configuration options for creating a parser. Most options specify which +// fields should be included, while others enable features. If a field is not +// included the parser will assume a default value. These options do not change +// the order fields are parse in. +type ParseOption int + +const ( + Second ParseOption = 1 << iota // Seconds field, default 0 + SecondOptional // Optional seconds field, default 0 + Minute // Minutes field, default 0 + Hour // Hours field, default 0 + Dom // Day of month field, default * + Month // Month field, default * + Dow // Day of week field, default * + DowOptional // Optional day of week field, default * + Descriptor // Allow descriptors such as @monthly, @weekly, etc. +) + +var places = []ParseOption{ + Second, + Minute, + Hour, + Dom, + Month, + Dow, +} + +var defaults = []string{ + "0", + "0", + "0", + "*", + "*", + "*", +} + +// A custom Parser that can be configured. +type Parser struct { + options ParseOption +} + +// NewParser creates a Parser with custom options. +// +// It panics if more than one Optional is given, since it would be impossible to +// correctly infer which optional is provided or missing in general. +// +// Examples +// +// // Standard parser without descriptors +// specParser := NewParser(Minute | Hour | Dom | Month | Dow) +// sched, err := specParser.Parse("0 0 15 */3 *") +// +// // Same as above, just excludes time fields +// subsParser := NewParser(Dom | Month | Dow) +// sched, err := specParser.Parse("15 */3 *") +// +// // Same as above, just makes Dow optional +// subsParser := NewParser(Dom | Month | DowOptional) +// sched, err := specParser.Parse("15 */3") +// +func NewParser(options ParseOption) Parser { + optionals := 0 + if options&DowOptional > 0 { + optionals++ + } + if options&SecondOptional > 0 { + optionals++ + } + if optionals > 1 { + panic("multiple optionals may not be configured") + } + return Parser{options} +} + +// Parse returns a new crontab schedule representing the given spec. +// It returns a descriptive error if the spec is not valid. +// It accepts crontab specs and features configured by NewParser. +func (p Parser) Parse(spec string) (Schedule, error) { + if len(spec) == 0 { + return nil, fmt.Errorf("empty spec string") + } + + // Extract timezone if present + var loc = time.Local + if strings.HasPrefix(spec, "TZ=") || strings.HasPrefix(spec, "CRON_TZ=") { + var err error + i := strings.Index(spec, " ") + eq := strings.Index(spec, "=") + if loc, err = time.LoadLocation(spec[eq+1 : i]); err != nil { + return nil, fmt.Errorf("provided bad location %s: %v", spec[eq+1:i], err) + } + spec = strings.TrimSpace(spec[i:]) + } + + // Handle named schedules (descriptors), if configured + if strings.HasPrefix(spec, "@") { + if p.options&Descriptor == 0 { + return nil, fmt.Errorf("parser does not accept descriptors: %v", spec) + } + return parseDescriptor(spec, loc) + } + + // Split on whitespace. + fields := strings.Fields(spec) + + // Validate & fill in any omitted or optional fields + var err error + fields, err = normalizeFields(fields, p.options) + if err != nil { + return nil, err + } + + field := func(field string, r bounds) uint64 { + if err != nil { + return 0 + } + var bits uint64 + bits, err = getField(field, r) + return bits + } + + var ( + second = field(fields[0], seconds) + minute = field(fields[1], minutes) + hour = field(fields[2], hours) + dayofmonth = field(fields[3], dom) + month = field(fields[4], months) + dayofweek = field(fields[5], dow) + ) + if err != nil { + return nil, err + } + + return &SpecSchedule{ + Second: second, + Minute: minute, + Hour: hour, + Dom: dayofmonth, + Month: month, + Dow: dayofweek, + Location: loc, + }, nil +} + +// normalizeFields takes a subset set of the time fields and returns the full set +// with defaults (zeroes) populated for unset fields. +// +// As part of performing this function, it also validates that the provided +// fields are compatible with the configured options. +func normalizeFields(fields []string, options ParseOption) ([]string, error) { + // Validate optionals & add their field to options + optionals := 0 + if options&SecondOptional > 0 { + options |= Second + optionals++ + } + if options&DowOptional > 0 { + options |= Dow + optionals++ + } + if optionals > 1 { + return nil, fmt.Errorf("multiple optionals may not be configured") + } + + // Figure out how many fields we need + max := 0 + for _, place := range places { + if options&place > 0 { + max++ + } + } + min := max - optionals + + // Validate number of fields + if count := len(fields); count < min || count > max { + if min == max { + return nil, fmt.Errorf("expected exactly %d fields, found %d: %s", min, count, fields) + } + return nil, fmt.Errorf("expected %d to %d fields, found %d: %s", min, max, count, fields) + } + + // Populate the optional field if not provided + if min < max && len(fields) == min { + switch { + case options&DowOptional > 0: + fields = append(fields, defaults[5]) // TODO: improve access to default + case options&SecondOptional > 0: + fields = append([]string{defaults[0]}, fields...) + default: + return nil, fmt.Errorf("unknown optional field") + } + } + + // Populate all fields not part of options with their defaults + n := 0 + expandedFields := make([]string, len(places)) + copy(expandedFields, defaults) + for i, place := range places { + if options&place > 0 { + expandedFields[i] = fields[n] + n++ + } + } + return expandedFields, nil +} + +var standardParser = NewParser( + Minute | Hour | Dom | Month | Dow | Descriptor, +) + +// ParseStandard returns a new crontab schedule representing the given +// standardSpec (https://en.wikipedia.org/wiki/Cron). It requires 5 entries +// representing: minute, hour, day of month, month and day of week, in that +// order. It returns a descriptive error if the spec is not valid. +// +// It accepts +// - Standard crontab specs, e.g. "* * * * ?" +// - Descriptors, e.g. "@midnight", "@every 1h30m" +func ParseStandard(standardSpec string) (Schedule, error) { + return standardParser.Parse(standardSpec) +} + +// getField returns an Int with the bits set representing all of the times that +// the field represents or error parsing field value. A "field" is a comma-separated +// list of "ranges". +func getField(field string, r bounds) (uint64, error) { + var bits uint64 + ranges := strings.FieldsFunc(field, func(r rune) bool { return r == ',' }) + for _, expr := range ranges { + bit, err := getRange(expr, r) + if err != nil { + return bits, err + } + bits |= bit + } + return bits, nil +} + +// getRange returns the bits indicated by the given expression: +// number | number "-" number [ "/" number ] +// or error parsing range. +func getRange(expr string, r bounds) (uint64, error) { + var ( + start, end, step uint + rangeAndStep = strings.Split(expr, "/") + lowAndHigh = strings.Split(rangeAndStep[0], "-") + singleDigit = len(lowAndHigh) == 1 + err error + ) + + var extra uint64 + if lowAndHigh[0] == "*" || lowAndHigh[0] == "?" { + start = r.min + end = r.max + extra = starBit + } else { + start, err = parseIntOrName(lowAndHigh[0], r.names) + if err != nil { + return 0, err + } + switch len(lowAndHigh) { + case 1: + end = start + case 2: + end, err = parseIntOrName(lowAndHigh[1], r.names) + if err != nil { + return 0, err + } + default: + return 0, fmt.Errorf("too many hyphens: %s", expr) + } + } + + switch len(rangeAndStep) { + case 1: + step = 1 + case 2: + step, err = mustParseInt(rangeAndStep[1]) + if err != nil { + return 0, err + } + + // Special handling: "N/step" means "N-max/step". + if singleDigit { + end = r.max + } + if step > 1 { + extra = 0 + } + default: + return 0, fmt.Errorf("too many slashes: %s", expr) + } + + if start < r.min { + return 0, fmt.Errorf("beginning of range (%d) below minimum (%d): %s", start, r.min, expr) + } + if end > r.max { + return 0, fmt.Errorf("end of range (%d) above maximum (%d): %s", end, r.max, expr) + } + if start > end { + return 0, fmt.Errorf("beginning of range (%d) beyond end of range (%d): %s", start, end, expr) + } + if step == 0 { + return 0, fmt.Errorf("step of range should be a positive number: %s", expr) + } + + return getBits(start, end, step) | extra, nil +} + +// parseIntOrName returns the (possibly-named) integer contained in expr. +func parseIntOrName(expr string, names map[string]uint) (uint, error) { + if names != nil { + if namedInt, ok := names[strings.ToLower(expr)]; ok { + return namedInt, nil + } + } + return mustParseInt(expr) +} + +// mustParseInt parses the given expression as an int or returns an error. +func mustParseInt(expr string) (uint, error) { + num, err := strconv.Atoi(expr) + if err != nil { + return 0, fmt.Errorf("failed to parse int from %s: %s", expr, err) + } + if num < 0 { + return 0, fmt.Errorf("negative number (%d) not allowed: %s", num, expr) + } + + return uint(num), nil +} + +// getBits sets all bits in the range [min, max], modulo the given step size. +func getBits(min, max, step uint) uint64 { + var bits uint64 + + // If step is 1, use shifts. + if step == 1 { + return ^(math.MaxUint64 << (max + 1)) & (math.MaxUint64 << min) + } + + // Else, use a simple loop. + for i := min; i <= max; i += step { + bits |= 1 << i + } + return bits +} + +// all returns all bits within the given bounds. (plus the star bit) +func all(r bounds) uint64 { + return getBits(r.min, r.max, 1) | starBit +} + +// parseDescriptor returns a predefined schedule for the expression, or error if none matches. +func parseDescriptor(descriptor string, loc *time.Location) (Schedule, error) { + switch descriptor { + case "@yearly", "@annually": + return &SpecSchedule{ + Second: 1 << seconds.min, + Minute: 1 << minutes.min, + Hour: 1 << hours.min, + Dom: 1 << dom.min, + Month: 1 << months.min, + Dow: all(dow), + Location: loc, + }, nil + + case "@monthly": + return &SpecSchedule{ + Second: 1 << seconds.min, + Minute: 1 << minutes.min, + Hour: 1 << hours.min, + Dom: 1 << dom.min, + Month: all(months), + Dow: all(dow), + Location: loc, + }, nil + + case "@weekly": + return &SpecSchedule{ + Second: 1 << seconds.min, + Minute: 1 << minutes.min, + Hour: 1 << hours.min, + Dom: all(dom), + Month: all(months), + Dow: 1 << dow.min, + Location: loc, + }, nil + + case "@daily", "@midnight": + return &SpecSchedule{ + Second: 1 << seconds.min, + Minute: 1 << minutes.min, + Hour: 1 << hours.min, + Dom: all(dom), + Month: all(months), + Dow: all(dow), + Location: loc, + }, nil + + case "@hourly": + return &SpecSchedule{ + Second: 1 << seconds.min, + Minute: 1 << minutes.min, + Hour: all(hours), + Dom: all(dom), + Month: all(months), + Dow: all(dow), + Location: loc, + }, nil + + } + + const every = "@every " + if strings.HasPrefix(descriptor, every) { + duration, err := time.ParseDuration(descriptor[len(every):]) + if err != nil { + return nil, fmt.Errorf("failed to parse duration %s: %s", descriptor, err) + } + return Every(duration), nil + } + + return nil, fmt.Errorf("unrecognized descriptor: %s", descriptor) +} diff --git a/vendor/github.com/robfig/cron/v3/spec.go b/vendor/github.com/robfig/cron/v3/spec.go new file mode 100644 index 000000000..fa1e241e5 --- /dev/null +++ b/vendor/github.com/robfig/cron/v3/spec.go @@ -0,0 +1,188 @@ +package cron + +import "time" + +// SpecSchedule specifies a duty cycle (to the second granularity), based on a +// traditional crontab specification. It is computed initially and stored as bit sets. +type SpecSchedule struct { + Second, Minute, Hour, Dom, Month, Dow uint64 + + // Override location for this schedule. + Location *time.Location +} + +// bounds provides a range of acceptable values (plus a map of name to value). +type bounds struct { + min, max uint + names map[string]uint +} + +// The bounds for each field. +var ( + seconds = bounds{0, 59, nil} + minutes = bounds{0, 59, nil} + hours = bounds{0, 23, nil} + dom = bounds{1, 31, nil} + months = bounds{1, 12, map[string]uint{ + "jan": 1, + "feb": 2, + "mar": 3, + "apr": 4, + "may": 5, + "jun": 6, + "jul": 7, + "aug": 8, + "sep": 9, + "oct": 10, + "nov": 11, + "dec": 12, + }} + dow = bounds{0, 6, map[string]uint{ + "sun": 0, + "mon": 1, + "tue": 2, + "wed": 3, + "thu": 4, + "fri": 5, + "sat": 6, + }} +) + +const ( + // Set the top bit if a star was included in the expression. + starBit = 1 << 63 +) + +// Next returns the next time this schedule is activated, greater than the given +// time. If no time can be found to satisfy the schedule, return the zero time. +func (s *SpecSchedule) Next(t time.Time) time.Time { + // General approach + // + // For Month, Day, Hour, Minute, Second: + // Check if the time value matches. If yes, continue to the next field. + // If the field doesn't match the schedule, then increment the field until it matches. + // While incrementing the field, a wrap-around brings it back to the beginning + // of the field list (since it is necessary to re-verify previous field + // values) + + // Convert the given time into the schedule's timezone, if one is specified. + // Save the original timezone so we can convert back after we find a time. + // Note that schedules without a time zone specified (time.Local) are treated + // as local to the time provided. + origLocation := t.Location() + loc := s.Location + if loc == time.Local { + loc = t.Location() + } + if s.Location != time.Local { + t = t.In(s.Location) + } + + // Start at the earliest possible time (the upcoming second). + t = t.Add(1*time.Second - time.Duration(t.Nanosecond())*time.Nanosecond) + + // This flag indicates whether a field has been incremented. + added := false + + // If no time is found within five years, return zero. + yearLimit := t.Year() + 5 + +WRAP: + if t.Year() > yearLimit { + return time.Time{} + } + + // Find the first applicable month. + // If it's this month, then do nothing. + for 1< 12 { + t = t.Add(time.Duration(24-t.Hour()) * time.Hour) + } else { + t = t.Add(time.Duration(-t.Hour()) * time.Hour) + } + } + + if t.Day() == 1 { + goto WRAP + } + } + + for 1< 0 + dowMatch bool = 1< 0 + ) + if s.Dom&starBit > 0 || s.Dow&starBit > 0 { + return domMatch && dowMatch + } + return domMatch || dowMatch +} diff --git a/vendor/modules.txt b/vendor/modules.txt index 9bc08057b..3a6e6643e 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -416,7 +416,7 @@ github.com/google/go-containerregistry/pkg/v1/types github.com/google/go-querystring/query # github.com/google/gofuzz v1.1.0 => github.com/google/gofuzz v1.1.0 github.com/google/gofuzz -# github.com/google/gops v0.3.23 +# github.com/google/gops v0.3.23 => github.com/google/gops v0.3.23 ## explicit github.com/google/gops/agent github.com/google/gops/internal @@ -811,6 +811,8 @@ github.com/prometheus/prometheus/util/testutil github.com/rainycape/unidecode # github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a => github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a github.com/rcrowley/go-metrics +# github.com/robfig/cron/v3 v3.0.1 => github.com/robfig/cron/v3 v3.0.1 +github.com/robfig/cron/v3 # github.com/rubenv/sql-migrate v0.0.0-20200616145509-8d140a17f351 => github.com/rubenv/sql-migrate v0.0.0-20200616145509-8d140a17f351 github.com/rubenv/sql-migrate github.com/rubenv/sql-migrate/sqlparse @@ -818,10 +820,6 @@ github.com/rubenv/sql-migrate/sqlparse github.com/russross/blackfriday # github.com/sergi/go-diff v1.1.0 => github.com/sergi/go-diff v1.0.0 github.com/sergi/go-diff/diffmatchpatch -# github.com/shirou/gopsutil v0.0.0-20180427012116-c95755e4bcd7 -## explicit -# github.com/shirou/w32 v0.0.0-20160930032740-bb4de0191aa4 -## explicit # github.com/sirupsen/logrus v1.8.1 => github.com/sirupsen/logrus v1.4.2 github.com/sirupsen/logrus # github.com/sony/sonyflake v0.0.0-20181109022403-6d5bd6181009 => github.com/sony/sonyflake v0.0.0-20181109022403-6d5bd6181009 @@ -2004,6 +2002,7 @@ kubesphere.io/api/tenant/crdinstall kubesphere.io/api/tenant/v1alpha1 kubesphere.io/api/tenant/v1alpha2 kubesphere.io/api/types/v1beta1 +kubesphere.io/api/types/v1beta2 # kubesphere.io/client-go v0.0.0 => ./staging/src/kubesphere.io/client-go ## explicit kubesphere.io/client-go/client @@ -2234,6 +2233,7 @@ sigs.k8s.io/yaml # github.com/Shopify/logrus-bugsnag => github.com/Shopify/logrus-bugsnag v0.0.0-20171204204709-577dee27f20d # github.com/Shopify/sarama => github.com/Shopify/sarama v1.19.0 # github.com/Shopify/toxiproxy => github.com/Shopify/toxiproxy v2.1.4+incompatible +# github.com/StackExchange/wmi => github.com/StackExchange/wmi v1.2.1 # github.com/VividCortex/gohistogram => github.com/VividCortex/gohistogram v1.0.0 # github.com/afex/hystrix-go => github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5 # github.com/agnivade/levenshtein => github.com/agnivade/levenshtein v1.0.1 @@ -2397,6 +2397,7 @@ sigs.k8s.io/yaml # github.com/go-logfmt/logfmt => github.com/go-logfmt/logfmt v0.5.0 # github.com/go-logr/logr => github.com/go-logr/logr v0.4.0 # github.com/go-logr/zapr => github.com/go-logr/zapr v0.4.0 +# github.com/go-ole/go-ole => github.com/go-ole/go-ole v1.2.6-0.20210915003542-8b1f7f90f6b1 # github.com/go-openapi/analysis => github.com/go-openapi/analysis v0.19.10 # github.com/go-openapi/errors => github.com/go-openapi/errors v0.19.4 # github.com/go-openapi/jsonpointer => github.com/go-openapi/jsonpointer v0.19.3 @@ -2459,6 +2460,7 @@ sigs.k8s.io/yaml # github.com/google/go-github => github.com/google/go-github v17.0.0+incompatible # github.com/google/go-querystring => github.com/google/go-querystring v1.0.0 # github.com/google/gofuzz => github.com/google/gofuzz v1.1.0 +# github.com/google/gops => github.com/google/gops v0.3.23 # github.com/google/martian => github.com/google/martian v2.1.0+incompatible # github.com/google/pprof => github.com/google/pprof v0.0.0-20200417002340-c6e0a841f49a # github.com/google/renameio => github.com/google/renameio v0.1.0 @@ -2542,6 +2544,7 @@ sigs.k8s.io/yaml # github.com/karrick/godirwalk => github.com/karrick/godirwalk v1.10.3 # github.com/kelseyhightower/envconfig => github.com/kelseyhightower/envconfig v1.4.0 # github.com/kevinburke/ssh_config => github.com/kevinburke/ssh_config v0.0.0-20180830205328-81db2a75821e +# github.com/keybase/go-ps => github.com/keybase/go-ps v0.0.0-20190827175125-91aafc93ba19 # github.com/kisielk/errcheck => github.com/kisielk/errcheck v1.2.0 # github.com/kisielk/gotool => github.com/kisielk/gotool v1.0.0 # github.com/kisielk/sqlstruct => github.com/kisielk/sqlstruct v0.0.0-20150923205031-648daed35d49 @@ -2690,6 +2693,7 @@ sigs.k8s.io/yaml # github.com/rainycape/unidecode => github.com/rainycape/unidecode v0.0.0-20150907023854-cb7f23ec59be # github.com/rcrowley/go-metrics => github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a # github.com/retailnext/hllpp => github.com/retailnext/hllpp v1.0.1-0.20180308014038-101a6d2f8b52 +# github.com/robfig/cron/v3 => github.com/robfig/cron/v3 v3.0.1 # github.com/rogpeppe/fastuuid => github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af # github.com/rogpeppe/go-charset => github.com/rogpeppe/go-charset v0.0.0-20180617210344-2471d30d28b4 # github.com/rogpeppe/go-internal => github.com/rogpeppe/go-internal v1.3.0 @@ -2706,6 +2710,9 @@ sigs.k8s.io/yaml # github.com/segmentio/kafka-go => github.com/segmentio/kafka-go v0.2.0 # github.com/sercand/kuberesolver => github.com/sercand/kuberesolver v2.4.0+incompatible # github.com/sergi/go-diff => github.com/sergi/go-diff v1.0.0 +# github.com/shirou/gopsutil => github.com/shirou/gopsutil v0.0.0-20180427012116-c95755e4bcd7 +# github.com/shirou/gopsutil/v3 => github.com/shirou/gopsutil/v3 v3.21.9 +# github.com/shirou/w32 => github.com/shirou/w32 v0.0.0-20160930032740-bb4de0191aa4 # github.com/shopspring/decimal => github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24 # github.com/shurcooL/httpfs => github.com/shurcooL/httpfs v0.0.0-20190707220628-8d4bc4ba7749 # github.com/shurcooL/sanitized_anchor_name => github.com/shurcooL/sanitized_anchor_name v1.0.0 @@ -2734,6 +2741,8 @@ sigs.k8s.io/yaml # github.com/thanos-io/thanos => github.com/thanos-io/thanos v0.13.1-0.20200910143741-e0b7f7b32e9c # github.com/tidwall/pretty => github.com/tidwall/pretty v1.0.0 # github.com/tinylib/msgp => github.com/tinylib/msgp v1.1.0 +# github.com/tklauser/go-sysconf => github.com/tklauser/go-sysconf v0.3.9 +# github.com/tklauser/numcpus => github.com/tklauser/numcpus v0.3.0 # github.com/tmc/grpc-websocket-proxy => github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5 # github.com/tv42/httpunix => github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926 # github.com/uber/jaeger-client-go => github.com/uber/jaeger-client-go v2.23.0+incompatible @@ -2864,6 +2873,7 @@ sigs.k8s.io/yaml # kubesphere.io/client-go => ./staging/src/kubesphere.io/client-go # kubesphere.io/monitoring-dashboard => kubesphere.io/monitoring-dashboard v0.2.2 # rsc.io/binaryregexp => rsc.io/binaryregexp v0.2.0 +# rsc.io/goversion => rsc.io/goversion v1.2.0 # rsc.io/letsencrypt => rsc.io/letsencrypt v0.0.1 # rsc.io/pdf => rsc.io/pdf v0.1.1 # rsc.io/quote/v3 => rsc.io/quote/v3 v3.1.0