diff --git a/build/test/integration_test.go b/build/test/integration_test.go index 0fb954c1bd..cee733da5b 100644 --- a/build/test/integration_test.go +++ b/build/test/integration_test.go @@ -318,7 +318,7 @@ func TestEgctlCmd(t *testing.T) { output, stderr, err := runCmd(cmd) assert.NoError(err) assert.Empty(stderr) - head := []string{"NAME", "ALIASES", "KIND", "ACTION"} + head := []string{"NAME", "ALIASES", "CATEGORY", "KIND", "ACTION"} assert.True(matchTable(head, output)) assert.True(matchTable([]string{"member", "m,mem,members", "Member", "delete,get,describe"}, output)) assert.Contains(output, "create,apply,delete,get,describe") @@ -623,7 +623,7 @@ func TestLogs(t *testing.T) { // check if new logs are printed yamlStr := ` kind: HTTPServer -name: test-egctl-logs +name: test-egctl-logs port: 12345 rules: - paths: diff --git a/cmd/client/commandv2/general.go b/cmd/client/commandv2/general.go index c4d88d73b7..9b5c846de2 100644 --- a/cmd/client/commandv2/general.go +++ b/cmd/client/commandv2/general.go @@ -134,13 +134,13 @@ func APIResourcesCmd() *cobra.Command { sort.Slice(r.Aliases, func(i, j int) bool { return len(r.Aliases[i]) < len(r.Aliases[j]) }) - tables = append(tables, []string{r.Name, strings.Join(r.Aliases, ","), r.Kind, action}) + tables = append(tables, []string{r.Name, strings.Join(r.Aliases, ","), r.Category, r.Kind, action}) } sort.Slice(tables, func(i, j int) bool { return tables[i][0] < tables[j][0] }) - tables = append([][]string{{"NAME", "ALIASES", "KIND", "ACTION"}}, tables...) + tables = append([][]string{{"NAME", "ALIASES", "CATEGORY", "KIND", "ACTION"}}, tables...) tables = append(tables, []string{cdk.Name, strings.Join(cdk.Aliases, ","), cdk.Kind, action}) tables = append(tables, []string{cd.Name, strings.Join(cd.Aliases, ","), cd.Kind, action}) tables = append(tables, []string{member.Name, strings.Join(member.Aliases, ","), member.Kind, "delete,get,describe"}) diff --git a/pkg/api/object.go b/pkg/api/object.go index 83b879c018..2658dabce4 100644 --- a/pkg/api/object.go +++ b/pkg/api/object.go @@ -138,6 +138,10 @@ func (s *Server) createObject(w http.ResponseWriter, r *http.Request) { return } + if spec.Categroy() == supervisor.CategorySystemController { + HandleAPIError(w, r, http.StatusConflict, fmt.Errorf("can't create system controller object")) + } + name := spec.Name() s.Lock() @@ -164,6 +168,12 @@ func (s *Server) deleteObject(w http.ResponseWriter, r *http.Request) { defer s.Unlock() spec := s._getObject(name) + + if spec.Categroy() == supervisor.CategorySystemController { + HandleAPIError(w, r, http.StatusBadRequest, fmt.Errorf("can't delete system controller object")) + return + } + if spec == nil { HandleAPIError(w, r, http.StatusNotFound, fmt.Errorf("not found")) return diff --git a/pkg/api/registry.go b/pkg/api/registry.go index 980c6c5a15..5f3ce3a520 100644 --- a/pkg/api/registry.go +++ b/pkg/api/registry.go @@ -23,13 +23,14 @@ import ( ) type APIResource struct { - Kind string - Name string - Aliases []string + Category string + Kind string + Name string + Aliases []string } // key is Kind name, now only contains api resource of object. -var objectApiResource = map[string]*APIResource{} +var objectAPIResource = map[string]*APIResource{} func RegisterObject(r *APIResource) { if r.Kind == "" { @@ -39,16 +40,16 @@ func RegisterObject(r *APIResource) { panic(fmt.Errorf("%v: empty name", r)) } - existedObject, existed := objectApiResource[r.Kind] + existedObject, existed := objectAPIResource[r.Kind] if existed { panic(fmt.Errorf("%v and %v got same kind: %s", r, existedObject, r.Kind)) } - objectApiResource[r.Kind] = r + objectAPIResource[r.Kind] = r } func ObjectAPIResources() []*APIResource { resources := []*APIResource{} - for _, r := range objectApiResource { + for _, r := range objectAPIResource { resources = append(resources, r) } return resources diff --git a/pkg/object/autocertmanager/autocertmanager.go b/pkg/object/autocertmanager/autocertmanager.go index 524e9b90ea..057c31dc6c 100644 --- a/pkg/object/autocertmanager/autocertmanager.go +++ b/pkg/object/autocertmanager/autocertmanager.go @@ -55,9 +55,10 @@ var aliases = []string{ func init() { supervisor.Register(&AutoCertManager{}) api.RegisterObject(&api.APIResource{ - Kind: Kind, - Name: strings.ToLower(Kind), - Aliases: aliases, + Category: Category, + Kind: Kind, + Name: strings.ToLower(Kind), + Aliases: aliases, }) } diff --git a/pkg/object/consulserviceregistry/consulserviceregistry.go b/pkg/object/consulserviceregistry/consulserviceregistry.go index b367d79191..7ac4e3c965 100644 --- a/pkg/object/consulserviceregistry/consulserviceregistry.go +++ b/pkg/object/consulserviceregistry/consulserviceregistry.go @@ -50,9 +50,10 @@ var aliases = []string{"consul", "consulserviceregistrys"} func init() { supervisor.Register(&ConsulServiceRegistry{}) egapi.RegisterObject(&egapi.APIResource{ - Kind: Kind, - Name: strings.ToLower(Kind), - Aliases: aliases, + Category: Category, + Kind: Kind, + Name: strings.ToLower(Kind), + Aliases: aliases, }) } diff --git a/pkg/object/easemonitormetrics/easemonitormetrics.go b/pkg/object/easemonitormetrics/easemonitormetrics.go index 71a3f8f366..e6921a532c 100644 --- a/pkg/object/easemonitormetrics/easemonitormetrics.go +++ b/pkg/object/easemonitormetrics/easemonitormetrics.go @@ -37,6 +37,9 @@ import ( ) const ( + // Category is the category of EaseMonitorMetrics. + Category = supervisor.CategoryBusinessController + // Kind is EaseMonitorMetrics kind. Kind = "EaseMonitorMetrics" ) @@ -54,9 +57,10 @@ func init() { } api.RegisterObject(&api.APIResource{ - Kind: Kind, - Name: strings.ToLower(Kind), - Aliases: aliases, + Category: Category, + Kind: Kind, + Name: strings.ToLower(Kind), + Aliases: aliases, }) } diff --git a/pkg/object/etcdserviceregistry/etcdserviceregistry.go b/pkg/object/etcdserviceregistry/etcdserviceregistry.go index 393ab4ee20..0e3681f48e 100644 --- a/pkg/object/etcdserviceregistry/etcdserviceregistry.go +++ b/pkg/object/etcdserviceregistry/etcdserviceregistry.go @@ -50,9 +50,10 @@ var aliases = []string{"etcd"} func init() { supervisor.Register(&EtcdServiceRegistry{}) api.RegisterObject(&api.APIResource{ - Kind: Kind, - Name: strings.ToLower(Kind), - Aliases: aliases, + Category: Category, + Kind: Kind, + Name: strings.ToLower(Kind), + Aliases: aliases, }) } diff --git a/pkg/object/eurekaserviceregistry/eurekaserviceregistry.go b/pkg/object/eurekaserviceregistry/eurekaserviceregistry.go index 91521193fd..f87d8d388c 100644 --- a/pkg/object/eurekaserviceregistry/eurekaserviceregistry.go +++ b/pkg/object/eurekaserviceregistry/eurekaserviceregistry.go @@ -49,9 +49,10 @@ var aliases = []string{"eureka"} func init() { supervisor.Register(&EurekaServiceRegistry{}) api.RegisterObject(&api.APIResource{ - Kind: Kind, - Name: name, - Aliases: aliases, + Category: Category, + Kind: Kind, + Name: name, + Aliases: aliases, }) } diff --git a/pkg/object/function/faascontroller.go b/pkg/object/function/faascontroller.go index b6fc17f676..47f2d4fa59 100644 --- a/pkg/object/function/faascontroller.go +++ b/pkg/object/function/faascontroller.go @@ -44,9 +44,10 @@ var aliases = []string{ func init() { supervisor.Register(&FaasController{}) api.RegisterObject(&api.APIResource{ - Kind: Kind, - Name: strings.ToLower(Kind), - Aliases: aliases, + Category: Category, + Kind: Kind, + Name: strings.ToLower(Kind), + Aliases: aliases, }) } diff --git a/pkg/object/globalfilter/globalfilter.go b/pkg/object/globalfilter/globalfilter.go index 72ae3db944..1cb5d97246 100644 --- a/pkg/object/globalfilter/globalfilter.go +++ b/pkg/object/globalfilter/globalfilter.go @@ -43,9 +43,10 @@ var aliases = []string{"globalfilters"} func init() { supervisor.Register(&GlobalFilter{}) api.RegisterObject(&api.APIResource{ - Kind: Kind, - Name: strings.ToLower(Kind), - Aliases: aliases, + Category: Category, + Kind: Kind, + Name: strings.ToLower(Kind), + Aliases: aliases, }) } diff --git a/pkg/object/grpcserver/grpcserver.go b/pkg/object/grpcserver/grpcserver.go index d58c4e76d7..12a0b0789b 100644 --- a/pkg/object/grpcserver/grpcserver.go +++ b/pkg/object/grpcserver/grpcserver.go @@ -37,9 +37,10 @@ const ( func init() { supervisor.Register(&GRPCServer{}) api.RegisterObject(&api.APIResource{ - Kind: Kind, - Name: strings.ToLower(Kind), - Aliases: []string{"grpc"}, + Category: Category, + Kind: Kind, + Name: strings.ToLower(Kind), + Aliases: []string{"grpc"}, }) } diff --git a/pkg/object/httpserver/httpserver.go b/pkg/object/httpserver/httpserver.go index b6d86e4a6b..7415b32063 100644 --- a/pkg/object/httpserver/httpserver.go +++ b/pkg/object/httpserver/httpserver.go @@ -37,9 +37,10 @@ const ( func init() { supervisor.Register(&HTTPServer{}) api.RegisterObject(&api.APIResource{ - Kind: Kind, - Name: strings.ToLower(Kind), - Aliases: []string{"httpservers", "hs"}, + Category: Category, + Kind: Kind, + Name: strings.ToLower(Kind), + Aliases: []string{"httpservers", "hs"}, }) } diff --git a/pkg/object/ingresscontroller/ingresscontroller.go b/pkg/object/ingresscontroller/ingresscontroller.go index 993cd75cd7..a7b206ff34 100644 --- a/pkg/object/ingresscontroller/ingresscontroller.go +++ b/pkg/object/ingresscontroller/ingresscontroller.go @@ -45,9 +45,10 @@ const ( func init() { supervisor.Register(&IngressController{}) api.RegisterObject(&api.APIResource{ - Kind: Kind, - Name: strings.ToLower(Kind), - Aliases: []string{"ingresscontrollers", "ingress"}, + Category: Category, + Kind: Kind, + Name: strings.ToLower(Kind), + Aliases: []string{"ingresscontrollers", "ingress"}, }) } diff --git a/pkg/object/meshcontroller/meshcontroller.go b/pkg/object/meshcontroller/meshcontroller.go index d804da6ba8..87c70c206e 100644 --- a/pkg/object/meshcontroller/meshcontroller.go +++ b/pkg/object/meshcontroller/meshcontroller.go @@ -43,9 +43,10 @@ const ( func init() { supervisor.Register(&MeshController{}) egapi.RegisterObject(&egapi.APIResource{ - Kind: Kind, - Name: strings.ToLower(Kind), - Aliases: []string{"mesh", "meshcontrollers"}, + Category: Category, + Kind: Kind, + Name: strings.ToLower(Kind), + Aliases: []string{"mesh", "meshcontrollers"}, }) } diff --git a/pkg/object/mqttproxy/mqttproxy.go b/pkg/object/mqttproxy/mqttproxy.go index 38ce04a7f8..5d64bf3e56 100644 --- a/pkg/object/mqttproxy/mqttproxy.go +++ b/pkg/object/mqttproxy/mqttproxy.go @@ -45,9 +45,10 @@ var _ supervisor.TrafficObject = (*MQTTProxy)(nil) func init() { supervisor.Register(&MQTTProxy{}) api.RegisterObject(&api.APIResource{ - Kind: Kind, - Name: strings.ToLower(Kind), - Aliases: []string{"mqtt", "mp"}, + Category: Category, + Kind: Kind, + Name: strings.ToLower(Kind), + Aliases: []string{"mqtt", "mp"}, }) } diff --git a/pkg/object/nacosserviceregistry/nacosserviceregistry.go b/pkg/object/nacosserviceregistry/nacosserviceregistry.go index 174c3fabef..b59bbd5cff 100644 --- a/pkg/object/nacosserviceregistry/nacosserviceregistry.go +++ b/pkg/object/nacosserviceregistry/nacosserviceregistry.go @@ -55,9 +55,10 @@ const ( func init() { supervisor.Register(&NacosServiceRegistry{}) api.RegisterObject(&api.APIResource{ - Kind: Kind, - Name: strings.ToLower(Kind), - Aliases: []string{"nacos"}, + Category: Category, + Kind: Kind, + Name: strings.ToLower(Kind), + Aliases: []string{"nacos"}, }) } diff --git a/pkg/object/pipeline/pipeline.go b/pkg/object/pipeline/pipeline.go index e8faaa505a..e8c342914c 100644 --- a/pkg/object/pipeline/pipeline.go +++ b/pkg/object/pipeline/pipeline.go @@ -47,9 +47,10 @@ const ( func init() { supervisor.Register(&Pipeline{}) api.RegisterObject(&api.APIResource{ - Kind: Kind, - Name: strings.ToLower(Kind), - Aliases: []string{"pipelines", "pl"}, + Category: Category, + Kind: Kind, + Name: strings.ToLower(Kind), + Aliases: []string{"pipelines", "pl"}, }) } diff --git a/pkg/object/rawconfigtrafficcontroller/rawconfigtrafficcontroller.go b/pkg/object/rawconfigtrafficcontroller/rawconfigtrafficcontroller.go index 10aea56167..4314a8a3a0 100644 --- a/pkg/object/rawconfigtrafficcontroller/rawconfigtrafficcontroller.go +++ b/pkg/object/rawconfigtrafficcontroller/rawconfigtrafficcontroller.go @@ -20,7 +20,9 @@ package rawconfigtrafficcontroller import ( "fmt" + "strings" + "github.com/megaease/easegress/v2/pkg/api" "github.com/megaease/easegress/v2/pkg/context" "github.com/megaease/easegress/v2/pkg/logger" "github.com/megaease/easegress/v2/pkg/object/pipeline" @@ -47,7 +49,6 @@ type ( spec *Spec watcher *supervisor.ObjectEntityWatcher - tc *trafficcontroller.TrafficController namespace string done chan struct{} } @@ -58,6 +59,12 @@ type ( func init() { supervisor.Register(&RawConfigTrafficController{}) + api.RegisterObject(&api.APIResource{ + Category: Category, + Kind: Kind, + Name: strings.ToLower(Kind), + Aliases: []string{"rawconfigtrafficcontroller", "rctc"}, + }) } // Category returns the category of RawConfigTrafficController. @@ -78,18 +85,26 @@ func (rctc *RawConfigTrafficController) DefaultSpec() interface{} { // Init initializes RawConfigTrafficController. func (rctc *RawConfigTrafficController) Init(superSpec *supervisor.Spec) { rctc.superSpec, rctc.spec = superSpec, superSpec.ObjectSpec().(*Spec) - rctc.reload() + rctc.reload(nil) } // Inherit inherits previous generation of RawConfigTrafficController. -func (rctc *RawConfigTrafficController) Inherit(spec *supervisor.Spec, previousGeneration supervisor.Object) { - previousGeneration.Close() - rctc.Init(spec) +func (rctc *RawConfigTrafficController) Inherit(superSpec *supervisor.Spec, previousGeneration supervisor.Object) { + rctc.superSpec, rctc.spec = superSpec, superSpec.ObjectSpec().(*Spec) + + // Close will clean all the using resources. + prev := previousGeneration.(*RawConfigTrafficController) + watcher := prev.watcher + close(prev.done) + + rctc.reload(watcher) } // GetPipeline gets Pipeline within the default namespace func (rctc *RawConfigTrafficController) GetPipeline(name string) (context.Handler, bool) { - p, exist := rctc.tc.GetPipeline(DefaultNamespace, name) + tc := rctc.getTrafficController() + + p, exist := tc.GetPipeline(DefaultNamespace, name) if !exist { return nil, false } @@ -97,7 +112,23 @@ func (rctc *RawConfigTrafficController) GetPipeline(name string) (context.Handle return handler, true } -func (rctc *RawConfigTrafficController) reload() { +func (rctc *RawConfigTrafficController) reload(watcher *supervisor.ObjectEntityWatcher) { + rctc.namespace = DefaultNamespace + + rctc.watcher = watcher + if rctc.watcher == nil { + rctc.watcher = rctc.superSpec.Super().ObjectRegistry().NewWatcher(rctc.superSpec.Name(), + supervisor.FilterCategory( + supervisor.CategoryTrafficGate, + supervisor.CategoryPipeline)) + } + + rctc.done = make(chan struct{}) + + go rctc.run() +} + +func (rctc *RawConfigTrafficController) getTrafficController() *trafficcontroller.TrafficController { entity, exists := rctc.superSpec.Super().GetSystemController(trafficcontroller.Kind) if !exists { panic(fmt.Errorf("BUG: traffic controller not found")) @@ -107,16 +138,8 @@ func (rctc *RawConfigTrafficController) reload() { if !ok { panic(fmt.Errorf("BUG: want *TrafficController, got %T", entity.Instance())) } - rctc.tc = tc - rctc.namespace = DefaultNamespace - rctc.watcher = rctc.superSpec.Super().ObjectRegistry().NewWatcher(rctc.superSpec.Name(), - supervisor.FilterCategory( - supervisor.CategoryTrafficGate, - supervisor.CategoryPipeline)) - rctc.done = make(chan struct{}) - - go rctc.run() + return tc } func (rctc *RawConfigTrafficController) run() { @@ -131,14 +154,16 @@ func (rctc *RawConfigTrafficController) run() { } func (rctc *RawConfigTrafficController) handleEvent(event *supervisor.ObjectEntityWatcherEvent) { + tc := rctc.getTrafficController() + for name, entity := range event.Delete { var err error kind := entity.Spec().Kind() if kind == pipeline.Kind { - err = rctc.tc.DeletePipeline(DefaultNamespace, name) + err = tc.DeletePipeline(DefaultNamespace, name) } else if _, ok := supervisor.TrafficObjectKinds[kind]; ok { - err = rctc.tc.DeleteTrafficGate(DefaultNamespace, name) + err = tc.DeleteTrafficGate(DefaultNamespace, name) } else { logger.Errorf("BUG: unexpected kind %T", kind) } @@ -153,9 +178,9 @@ func (rctc *RawConfigTrafficController) handleEvent(event *supervisor.ObjectEnti kind := entity.Spec().Kind() if kind == pipeline.Kind { - _, err = rctc.tc.CreatePipeline(DefaultNamespace, entity) + _, err = tc.CreatePipeline(DefaultNamespace, entity) } else if _, ok := supervisor.TrafficObjectKinds[kind]; ok { - _, err = rctc.tc.CreateTrafficGate(DefaultNamespace, entity) + _, err = tc.CreateTrafficGate(DefaultNamespace, entity) } else { logger.Errorf("BUG: unexpected kind %T", kind) } @@ -170,9 +195,9 @@ func (rctc *RawConfigTrafficController) handleEvent(event *supervisor.ObjectEnti kind := entity.Instance().Kind() if kind == pipeline.Kind { - _, err = rctc.tc.UpdatePipeline(DefaultNamespace, entity) + _, err = tc.UpdatePipeline(DefaultNamespace, entity) } else if _, ok := supervisor.TrafficObjectKinds[kind]; ok { - _, err = rctc.tc.UpdateTrafficGate(DefaultNamespace, entity) + _, err = tc.UpdateTrafficGate(DefaultNamespace, entity) } else { logger.Errorf("BUG: unexpected kind %T", kind) } @@ -198,5 +223,6 @@ func (rctc *RawConfigTrafficController) Status() *supervisor.Status { func (rctc *RawConfigTrafficController) Close() { close(rctc.done) rctc.superSpec.Super().ObjectRegistry().CloseWatcher(rctc.superSpec.Name()) - rctc.tc.Clean(rctc.namespace) + tc := rctc.getTrafficController() + tc.Clean(rctc.namespace) } diff --git a/pkg/object/serviceregistry/serviceregistry.go b/pkg/object/serviceregistry/serviceregistry.go index 818d323f64..f580b60fcb 100644 --- a/pkg/object/serviceregistry/serviceregistry.go +++ b/pkg/object/serviceregistry/serviceregistry.go @@ -39,9 +39,10 @@ const ( func init() { supervisor.Register(&ServiceRegistry{}) api.RegisterObject(&api.APIResource{ - Kind: Kind, - Name: strings.ToLower(Kind), - Aliases: []string{"sr", "serviceregistries"}, + Category: Category, + Kind: Kind, + Name: strings.ToLower(Kind), + Aliases: []string{"sr", "serviceregistry"}, }) } @@ -54,7 +55,7 @@ type ( superSpec *supervisor.Spec spec *Spec - mutex sync.Mutex + mutex *sync.Mutex // The key is registry name. registryBuckets map[string]*registryBucket @@ -81,9 +82,6 @@ type ( // Spec describes ServiceRegistry. Spec struct { - // TODO: Support updating for system controller. - // Please notice some components may reference of old system controller - // after reloading, this should be fixed. SyncInterval string `json:"syncInterval" jsonschema:"required,format=duration"` } @@ -368,17 +366,25 @@ func (sr *ServiceRegistry) DefaultSpec() interface{} { // Init initializes ServiceRegistry. func (sr *ServiceRegistry) Init(superSpec *supervisor.Spec) { sr.superSpec, sr.spec = superSpec, superSpec.ObjectSpec().(*Spec) - sr.reload() + sr.reload(nil) } // Inherit inherits previous generation of ServiceRegistry. func (sr *ServiceRegistry) Inherit(superSpec *supervisor.Spec, previousGeneration supervisor.Object) { + sr.superSpec, sr.spec = superSpec, superSpec.ObjectSpec().(*Spec) + sr.reload(previousGeneration.(*ServiceRegistry)) previousGeneration.Close() - sr.Init(superSpec) } -func (sr *ServiceRegistry) reload() { - sr.registryBuckets = make(map[string]*registryBucket) +func (sr *ServiceRegistry) reload(previousGeneration *ServiceRegistry) { + if previousGeneration != nil { + sr.registryBuckets = previousGeneration.registryBuckets + sr.mutex = previousGeneration.mutex + } else { + sr.registryBuckets = make(map[string]*registryBucket) + sr.mutex = &sync.Mutex{} + } + sr.done = make(chan struct{}) } diff --git a/pkg/object/statussynccontroller/statussynccontroller.go b/pkg/object/statussynccontroller/statussynccontroller.go index 4b7850616b..fd5e3bfb2c 100644 --- a/pkg/object/statussynccontroller/statussynccontroller.go +++ b/pkg/object/statussynccontroller/statussynccontroller.go @@ -19,8 +19,10 @@ package statussynccontroller import ( "runtime/debug" + "strings" "sync" + "github.com/megaease/easegress/v2/pkg/api" "github.com/megaease/easegress/v2/pkg/cluster" "github.com/megaease/easegress/v2/pkg/logger" "github.com/megaease/easegress/v2/pkg/supervisor" @@ -123,6 +125,12 @@ func (s *statusUnit) marshal() ([]byte, error) { func init() { supervisor.Register(&StatusSyncController{}) + api.RegisterObject(&api.APIResource{ + Category: Category, + Kind: Kind, + Name: strings.ToLower(Kind), + Aliases: []string{"statussynccontroller", "ssc"}, + }) } // Category returns the category of StatusSyncController. diff --git a/pkg/object/trafficcontroller/trafficcontroller.go b/pkg/object/trafficcontroller/trafficcontroller.go index 9f093e861f..69e0343226 100644 --- a/pkg/object/trafficcontroller/trafficcontroller.go +++ b/pkg/object/trafficcontroller/trafficcontroller.go @@ -21,8 +21,10 @@ package trafficcontroller import ( "fmt" "runtime/debug" + "strings" "sync" + "github.com/megaease/easegress/v2/pkg/api" "github.com/megaease/easegress/v2/pkg/cluster" "github.com/megaease/easegress/v2/pkg/context" "github.com/megaease/easegress/v2/pkg/logger" @@ -97,6 +99,12 @@ var _ easemonitor.Metricer = (*TrafficObjectStatus)(nil) func init() { supervisor.Register(&TrafficController{}) + api.RegisterObject(&api.APIResource{ + Category: Category, + Kind: Kind, + Name: strings.ToLower(Kind), + Aliases: []string{"trafficcontroller", "tc"}, + }) } // ToMetrics implements easemonitor.Metricer. @@ -157,7 +165,7 @@ func (tc *TrafficController) Init(superSpec *supervisor.Spec) { // Inherit inherits previous generation of TrafficController. func (tc *TrafficController) Inherit(superSpec *supervisor.Spec, previousGeneration supervisor.Object) { - tc.superSpec, tc.super = superSpec, superSpec.Super() + tc.superSpec, tc.spec, tc.super = superSpec, superSpec.ObjectSpec().(*Spec), superSpec.Super() tc.reload(previousGeneration.(*TrafficController)) } diff --git a/pkg/object/zookeeperserviceregistry/zookeeperserviceregistry.go b/pkg/object/zookeeperserviceregistry/zookeeperserviceregistry.go index ba455b363c..eaaf8e237b 100644 --- a/pkg/object/zookeeperserviceregistry/zookeeperserviceregistry.go +++ b/pkg/object/zookeeperserviceregistry/zookeeperserviceregistry.go @@ -45,9 +45,10 @@ const ( func init() { supervisor.Register(&ZookeeperServiceRegistry{}) api.RegisterObject(&api.APIResource{ - Kind: Kind, - Name: strings.ToLower(Kind), - Aliases: []string{"zookeeper", "zk", "zkserviceregistries"}, + Category: Category, + Kind: Kind, + Name: strings.ToLower(Kind), + Aliases: []string{"zookeeper", "zk", "zkserviceregistries"}, }) } diff --git a/pkg/supervisor/object.go b/pkg/supervisor/object.go index 86d188ddc3..c350d8ae4a 100644 --- a/pkg/supervisor/object.go +++ b/pkg/supervisor/object.go @@ -308,10 +308,11 @@ func (or *ObjectRegistry) storeConfigInLocal(config map[string]string) { } buff.Write(configBuff) - err = os.Rename(or.configLocalPath, or.backupConfigLocalPath) - if err != nil { - logger.Errorf("rename %s to %s failed: %v", or.configLocalPath, or.backupConfigLocalPath, err) - return + if _, err := os.Stat(or.configLocalPath); err == nil { + err = os.Rename(or.configLocalPath, or.backupConfigLocalPath) + if err != nil { + logger.Errorf("rename %s to %s failed: %v", or.configLocalPath, or.backupConfigLocalPath, err) + } } err = os.WriteFile(or.configLocalPath, buff.Bytes(), 0o644) diff --git a/pkg/supervisor/spec.go b/pkg/supervisor/spec.go index 2a5a6b984b..7133f61809 100644 --- a/pkg/supervisor/spec.go +++ b/pkg/supervisor/spec.go @@ -34,6 +34,7 @@ type ( Spec struct { super *Supervisor + category ObjectCategory jsonConfig string meta *MetaSpec rawSpec map[string]interface{} @@ -141,6 +142,7 @@ func (s *Supervisor) newSpec(config string, created bool) (spec *Spec, err error jsonConfig := string(codectool.MustMarshalJSON(rawSpec)) + spec.category = rootObject.Category() spec.meta = meta spec.objectSpec = objectSpec spec.rawSpec = rawSpec @@ -159,6 +161,10 @@ func (s *Spec) MarshalJSON() ([]byte, error) { return []byte(s.jsonConfig), nil } +func (s *Spec) Categroy() ObjectCategory { + return s.category +} + // Name returns name. func (s *Spec) Name() string { return s.meta.Name } diff --git a/pkg/supervisor/supervisor.go b/pkg/supervisor/supervisor.go index de09ec9b33..18b6373e0d 100644 --- a/pkg/supervisor/supervisor.go +++ b/pkg/supervisor/supervisor.go @@ -91,7 +91,7 @@ func MustNew(opt *option.Options, cls cluster.Cluster) *Supervisor { s.objectRegistry = newObjectRegistry(s, initObjs, opt.ObjectsDumpInterval) s.watcher = s.objectRegistry.NewWatcher(watcherName, FilterCategory( // NOTE: SystemController is only initialized internally. - // CategorySystemController, + CategorySystemController, CategoryBusinessController)) globalSuper = s @@ -137,6 +137,26 @@ func (s *Supervisor) initSystemControllers() { entity.InitWithRecovery(nil /* muxMapper */) s.systemControllers.Store(kind, entity) + + s.syncSystemControllerInCluster(spec) + } +} + +func (s *Supervisor) syncSystemControllerInCluster(spec *Spec) { + value, err := s.cls.Get(s.cls.Layout().ConfigObjectKey(spec.Name())) + if err != nil { + panic(err) + } + + // NOTE: The spec is already in cluster. + if value != nil { + return + } + + err = s.cls.Put(s.cls.Layout().ConfigObjectKey(spec.Name()), + spec.JSONConfig()) + if err != nil { + panic(err) } } @@ -172,7 +192,16 @@ func (s *Supervisor) handleEvent(event *ObjectEntityWatcherEvent) { } for name, entity := range event.Create { - _, exists := s.businessControllers.Load(name) + // This will be caused from the stored system controller spec while the system launching. + previousEntity, exists := s.systemControllers.Load(name) + if exists { + logger.Infof("update %s", name) + entity.InheritWithRecovery(previousEntity.(*ObjectEntity), nil /* muxMapper */) + s.systemControllers.Store(name, entity) + continue + } + + _, exists = s.businessControllers.Load(name) if exists { logger.Errorf("BUG: create %s already existed", name) continue @@ -184,15 +213,27 @@ func (s *Supervisor) handleEvent(event *ObjectEntityWatcherEvent) { } for name, entity := range event.Update { - previousEntity, exists := s.businessControllers.Load(name) + isSystemController := false + + previousEntity, exists := s.systemControllers.Load(name) if !exists { - logger.Errorf("BUG: update %s not found", name) - continue + previousEntity, exists = s.businessControllers.Load(name) + if !exists { + logger.Errorf("BUG: update %s not found", name) + continue + } + } else { + isSystemController = true } logger.Infof("update %s", name) entity.InheritWithRecovery(previousEntity.(*ObjectEntity), nil /* muxMapper */) - s.businessControllers.Store(name, entity) + + if isSystemController { + s.systemControllers.Store(name, entity) + } else { + s.businessControllers.Store(name, entity) + } } }