fix race condition in config updating

This commit is contained in:
ginuerzh 2023-01-20 10:27:21 +08:00
parent 40360f0c6f
commit 93b40f4c86
13 changed files with 272 additions and 229 deletions

View File

@ -47,9 +47,10 @@ func createAdmission(ctx *gin.Context) {
return return
} }
cfg := config.Global() config.OnUpdate(func(c *config.Config) error {
cfg.Admissions = append(cfg.Admissions, &req.Data) c.Admissions = append(c.Admissions, &req.Data)
config.SetGlobal(cfg) return nil
})
ctx.JSON(http.StatusOK, Response{ ctx.JSON(http.StatusOK, Response{
Msg: "OK", Msg: "OK",
@ -102,14 +103,15 @@ func updateAdmission(ctx *gin.Context) {
return return
} }
cfg := config.Global() config.OnUpdate(func(c *config.Config) error {
for i := range cfg.Admissions { for i := range c.Admissions {
if cfg.Admissions[i].Name == req.Admission { if c.Admissions[i].Name == req.Admission {
cfg.Admissions[i] = &req.Data c.Admissions[i] = &req.Data
break break
}
} }
} return nil
config.SetGlobal(cfg) })
ctx.JSON(http.StatusOK, Response{ ctx.JSON(http.StatusOK, Response{
Msg: "OK", Msg: "OK",
@ -149,16 +151,17 @@ func deleteAdmission(ctx *gin.Context) {
} }
registry.AdmissionRegistry().Unregister(req.Admission) registry.AdmissionRegistry().Unregister(req.Admission)
cfg := config.Global() config.OnUpdate(func(c *config.Config) error {
admissiones := cfg.Admissions admissiones := c.Admissions
cfg.Admissions = nil c.Admissions = nil
for _, s := range admissiones { for _, s := range admissiones {
if s.Name == req.Admission { if s.Name == req.Admission {
continue continue
}
c.Admissions = append(c.Admissions, s)
} }
cfg.Admissions = append(cfg.Admissions, s) return nil
} })
config.SetGlobal(cfg)
ctx.JSON(http.StatusOK, Response{ ctx.JSON(http.StatusOK, Response{
Msg: "OK", Msg: "OK",

View File

@ -46,9 +46,10 @@ func createAuther(ctx *gin.Context) {
return return
} }
cfg := config.Global() config.OnUpdate(func(c *config.Config) error {
cfg.Authers = append(cfg.Authers, &req.Data) c.Authers = append(c.Authers, &req.Data)
config.SetGlobal(cfg) return nil
})
ctx.JSON(http.StatusOK, Response{ ctx.JSON(http.StatusOK, Response{
Msg: "OK", Msg: "OK",
@ -100,14 +101,15 @@ func updateAuther(ctx *gin.Context) {
return return
} }
cfg := config.Global() config.OnUpdate(func(c *config.Config) error {
for i := range cfg.Authers { for i := range c.Authers {
if cfg.Authers[i].Name == req.Auther { if c.Authers[i].Name == req.Auther {
cfg.Authers[i] = &req.Data c.Authers[i] = &req.Data
break break
}
} }
} return nil
config.SetGlobal(cfg) })
ctx.JSON(http.StatusOK, Response{ ctx.JSON(http.StatusOK, Response{
Msg: "OK", Msg: "OK",
@ -147,16 +149,17 @@ func deleteAuther(ctx *gin.Context) {
} }
registry.AutherRegistry().Unregister(req.Auther) registry.AutherRegistry().Unregister(req.Auther)
cfg := config.Global() config.OnUpdate(func(c *config.Config) error {
authers := cfg.Authers authers := c.Authers
cfg.Authers = nil c.Authers = nil
for _, s := range authers { for _, s := range authers {
if s.Name == req.Auther { if s.Name == req.Auther {
continue continue
}
c.Authers = append(c.Authers, s)
} }
cfg.Authers = append(cfg.Authers, s) return nil
} })
config.SetGlobal(cfg)
ctx.JSON(http.StatusOK, Response{ ctx.JSON(http.StatusOK, Response{
Msg: "OK", Msg: "OK",

View File

@ -47,9 +47,10 @@ func createBypass(ctx *gin.Context) {
return return
} }
cfg := config.Global() config.OnUpdate(func(c *config.Config) error {
cfg.Bypasses = append(cfg.Bypasses, &req.Data) c.Bypasses = append(c.Bypasses, &req.Data)
config.SetGlobal(cfg) return nil
})
ctx.JSON(http.StatusOK, Response{ ctx.JSON(http.StatusOK, Response{
Msg: "OK", Msg: "OK",
@ -102,14 +103,15 @@ func updateBypass(ctx *gin.Context) {
return return
} }
cfg := config.Global() config.OnUpdate(func(c *config.Config) error {
for i := range cfg.Bypasses { for i := range c.Bypasses {
if cfg.Bypasses[i].Name == req.Bypass { if c.Bypasses[i].Name == req.Bypass {
cfg.Bypasses[i] = &req.Data c.Bypasses[i] = &req.Data
break break
}
} }
} return nil
config.SetGlobal(cfg) })
ctx.JSON(http.StatusOK, Response{ ctx.JSON(http.StatusOK, Response{
Msg: "OK", Msg: "OK",
@ -149,16 +151,17 @@ func deleteBypass(ctx *gin.Context) {
} }
registry.BypassRegistry().Unregister(req.Bypass) registry.BypassRegistry().Unregister(req.Bypass)
cfg := config.Global() config.OnUpdate(func(c *config.Config) error {
bypasses := cfg.Bypasses bypasses := c.Bypasses
cfg.Bypasses = nil c.Bypasses = nil
for _, s := range bypasses { for _, s := range bypasses {
if s.Name == req.Bypass { if s.Name == req.Bypass {
continue continue
}
c.Bypasses = append(c.Bypasses, s)
} }
cfg.Bypasses = append(cfg.Bypasses, s) return nil
} })
config.SetGlobal(cfg)
ctx.JSON(http.StatusOK, Response{ ctx.JSON(http.StatusOK, Response{
Msg: "OK", Msg: "OK",

View File

@ -51,9 +51,10 @@ func createChain(ctx *gin.Context) {
return return
} }
cfg := config.Global() config.OnUpdate(func(c *config.Config) error {
cfg.Chains = append(cfg.Chains, &req.Data) c.Chains = append(c.Chains, &req.Data)
config.SetGlobal(cfg) return nil
})
ctx.JSON(http.StatusOK, Response{ ctx.JSON(http.StatusOK, Response{
Msg: "OK", Msg: "OK",
@ -111,14 +112,15 @@ func updateChain(ctx *gin.Context) {
return return
} }
cfg := config.Global() config.OnUpdate(func(c *config.Config) error {
for i := range cfg.Chains { for i := range c.Chains {
if cfg.Chains[i].Name == req.Chain { if c.Chains[i].Name == req.Chain {
cfg.Chains[i] = &req.Data c.Chains[i] = &req.Data
break break
}
} }
} return nil
config.SetGlobal(cfg) })
ctx.JSON(http.StatusOK, Response{ ctx.JSON(http.StatusOK, Response{
Msg: "OK", Msg: "OK",
@ -158,16 +160,17 @@ func deleteChain(ctx *gin.Context) {
} }
registry.ChainRegistry().Unregister(req.Chain) registry.ChainRegistry().Unregister(req.Chain)
cfg := config.Global() config.OnUpdate(func(c *config.Config) error {
chains := cfg.Chains chains := c.Chains
cfg.Chains = nil c.Chains = nil
for _, s := range chains { for _, s := range chains {
if s.Name == req.Chain { if s.Name == req.Chain {
continue continue
}
c.Chains = append(c.Chains, s)
} }
cfg.Chains = append(cfg.Chains, s) return nil
} })
config.SetGlobal(cfg)
ctx.JSON(http.StatusOK, Response{ ctx.JSON(http.StatusOK, Response{
Msg: "OK", Msg: "OK",

View File

@ -47,9 +47,10 @@ func createConnLimiter(ctx *gin.Context) {
return return
} }
cfg := config.Global() config.OnUpdate(func(c *config.Config) error {
cfg.CLimiters = append(cfg.CLimiters, &req.Data) c.CLimiters = append(c.CLimiters, &req.Data)
config.SetGlobal(cfg) return nil
})
ctx.JSON(http.StatusOK, Response{ ctx.JSON(http.StatusOK, Response{
Msg: "OK", Msg: "OK",
@ -102,14 +103,15 @@ func updateConnLimiter(ctx *gin.Context) {
return return
} }
cfg := config.Global() config.OnUpdate(func(c *config.Config) error {
for i := range cfg.Limiters { for i := range c.CLimiters {
if cfg.Limiters[i].Name == req.Limiter { if c.CLimiters[i].Name == req.Limiter {
cfg.Limiters[i] = &req.Data c.CLimiters[i] = &req.Data
break break
}
} }
} return nil
config.SetGlobal(cfg) })
ctx.JSON(http.StatusOK, Response{ ctx.JSON(http.StatusOK, Response{
Msg: "OK", Msg: "OK",
@ -149,16 +151,17 @@ func deleteConnLimiter(ctx *gin.Context) {
} }
registry.ConnLimiterRegistry().Unregister(req.Limiter) registry.ConnLimiterRegistry().Unregister(req.Limiter)
cfg := config.Global() config.OnUpdate(func(c *config.Config) error {
limiteres := cfg.Limiters limiteres := c.CLimiters
cfg.Limiters = nil c.CLimiters = nil
for _, s := range limiteres { for _, s := range limiteres {
if s.Name == req.Limiter { if s.Name == req.Limiter {
continue continue
}
c.CLimiters = append(c.CLimiters, s)
} }
cfg.Limiters = append(cfg.Limiters, s) return nil
} })
config.SetGlobal(cfg)
ctx.JSON(http.StatusOK, Response{ ctx.JSON(http.StatusOK, Response{
Msg: "OK", Msg: "OK",

View File

@ -51,9 +51,10 @@ func createHop(ctx *gin.Context) {
return return
} }
cfg := config.Global() config.OnUpdate(func(c *config.Config) error {
cfg.Hops = append(cfg.Hops, &req.Data) c.Hops = append(c.Hops, &req.Data)
config.SetGlobal(cfg) return nil
})
ctx.JSON(http.StatusOK, Response{ ctx.JSON(http.StatusOK, Response{
Msg: "OK", Msg: "OK",
@ -111,14 +112,15 @@ func updateHop(ctx *gin.Context) {
return return
} }
cfg := config.Global() config.OnUpdate(func(c *config.Config) error {
for i := range cfg.Hops { for i := range c.Hops {
if cfg.Hops[i].Name == req.Hop { if c.Hops[i].Name == req.Hop {
cfg.Hops[i] = &req.Data c.Hops[i] = &req.Data
break break
}
} }
} return nil
config.SetGlobal(cfg) })
ctx.JSON(http.StatusOK, Response{ ctx.JSON(http.StatusOK, Response{
Msg: "OK", Msg: "OK",
@ -158,16 +160,17 @@ func deleteHop(ctx *gin.Context) {
} }
registry.HopRegistry().Unregister(req.Hop) registry.HopRegistry().Unregister(req.Hop)
cfg := config.Global() config.OnUpdate(func(c *config.Config) error {
hops := cfg.Hops hops := c.Hops
cfg.Hops = nil c.Hops = nil
for _, s := range hops { for _, s := range hops {
if s.Name == req.Hop { if s.Name == req.Hop {
continue continue
}
c.Hops = append(c.Hops, s)
} }
cfg.Hops = append(cfg.Hops, s) return nil
} })
config.SetGlobal(cfg)
ctx.JSON(http.StatusOK, Response{ ctx.JSON(http.StatusOK, Response{
Msg: "OK", Msg: "OK",

View File

@ -47,9 +47,10 @@ func createHosts(ctx *gin.Context) {
return return
} }
cfg := config.Global() config.OnUpdate(func(c *config.Config) error {
cfg.Hosts = append(cfg.Hosts, &req.Data) c.Hosts = append(c.Hosts, &req.Data)
config.SetGlobal(cfg) return nil
})
ctx.JSON(http.StatusOK, Response{ ctx.JSON(http.StatusOK, Response{
Msg: "OK", Msg: "OK",
@ -102,14 +103,15 @@ func updateHosts(ctx *gin.Context) {
return return
} }
cfg := config.Global() config.OnUpdate(func(c *config.Config) error {
for i := range cfg.Hosts { for i := range c.Hosts {
if cfg.Hosts[i].Name == req.Hosts { if c.Hosts[i].Name == req.Hosts {
cfg.Hosts[i] = &req.Data c.Hosts[i] = &req.Data
break break
}
} }
} return nil
config.SetGlobal(cfg) })
ctx.JSON(http.StatusOK, Response{ ctx.JSON(http.StatusOK, Response{
Msg: "OK", Msg: "OK",
@ -149,16 +151,17 @@ func deleteHosts(ctx *gin.Context) {
} }
registry.HostsRegistry().Unregister(req.Hosts) registry.HostsRegistry().Unregister(req.Hosts)
cfg := config.Global() config.OnUpdate(func(c *config.Config) error {
hosts := cfg.Hosts hosts := c.Hosts
cfg.Hosts = nil c.Hosts = nil
for _, s := range hosts { for _, s := range hosts {
if s.Name == req.Hosts { if s.Name == req.Hosts {
continue continue
}
c.Hosts = append(c.Hosts, s)
} }
cfg.Hosts = append(cfg.Hosts, s) return nil
} })
config.SetGlobal(cfg)
ctx.JSON(http.StatusOK, Response{ ctx.JSON(http.StatusOK, Response{
Msg: "OK", Msg: "OK",

View File

@ -47,9 +47,10 @@ func createIngress(ctx *gin.Context) {
return return
} }
cfg := config.Global() config.OnUpdate(func(c *config.Config) error {
cfg.Ingresses = append(cfg.Ingresses, &req.Data) c.Ingresses = append(c.Ingresses, &req.Data)
config.SetGlobal(cfg) return nil
})
ctx.JSON(http.StatusOK, Response{ ctx.JSON(http.StatusOK, Response{
Msg: "OK", Msg: "OK",
@ -102,14 +103,15 @@ func updateIngress(ctx *gin.Context) {
return return
} }
cfg := config.Global() config.OnUpdate(func(c *config.Config) error {
for i := range cfg.Ingresses { for i := range c.Ingresses {
if cfg.Ingresses[i].Name == req.Ingress { if c.Ingresses[i].Name == req.Ingress {
cfg.Ingresses[i] = &req.Data c.Ingresses[i] = &req.Data
break break
}
} }
} return nil
config.SetGlobal(cfg) })
ctx.JSON(http.StatusOK, Response{ ctx.JSON(http.StatusOK, Response{
Msg: "OK", Msg: "OK",
@ -149,16 +151,17 @@ func deleteIngress(ctx *gin.Context) {
} }
registry.IngressRegistry().Unregister(req.Ingress) registry.IngressRegistry().Unregister(req.Ingress)
cfg := config.Global() config.OnUpdate(func(c *config.Config) error {
ingresses := cfg.Ingresses ingresses := c.Ingresses
cfg.Ingresses = nil c.Ingresses = nil
for _, s := range ingresses { for _, s := range ingresses {
if s.Name == req.Ingress { if s.Name == req.Ingress {
continue continue
}
c.Ingresses = append(c.Ingresses, s)
} }
cfg.Ingresses = append(cfg.Ingresses, s) return nil
} })
config.SetGlobal(cfg)
ctx.JSON(http.StatusOK, Response{ ctx.JSON(http.StatusOK, Response{
Msg: "OK", Msg: "OK",

View File

@ -47,9 +47,10 @@ func createLimiter(ctx *gin.Context) {
return return
} }
cfg := config.Global() config.OnUpdate(func(c *config.Config) error {
cfg.Limiters = append(cfg.Limiters, &req.Data) c.Limiters = append(c.Limiters, &req.Data)
config.SetGlobal(cfg) return nil
})
ctx.JSON(http.StatusOK, Response{ ctx.JSON(http.StatusOK, Response{
Msg: "OK", Msg: "OK",
@ -102,14 +103,15 @@ func updateLimiter(ctx *gin.Context) {
return return
} }
cfg := config.Global() config.OnUpdate(func(c *config.Config) error {
for i := range cfg.Limiters { for i := range c.Limiters {
if cfg.Limiters[i].Name == req.Limiter { if c.Limiters[i].Name == req.Limiter {
cfg.Limiters[i] = &req.Data c.Limiters[i] = &req.Data
break break
}
} }
} return nil
config.SetGlobal(cfg) })
ctx.JSON(http.StatusOK, Response{ ctx.JSON(http.StatusOK, Response{
Msg: "OK", Msg: "OK",
@ -149,16 +151,17 @@ func deleteLimiter(ctx *gin.Context) {
} }
registry.TrafficLimiterRegistry().Unregister(req.Limiter) registry.TrafficLimiterRegistry().Unregister(req.Limiter)
cfg := config.Global() config.OnUpdate(func(c *config.Config) error {
limiteres := cfg.Limiters limiteres := c.Limiters
cfg.Limiters = nil c.Limiters = nil
for _, s := range limiteres { for _, s := range limiteres {
if s.Name == req.Limiter { if s.Name == req.Limiter {
continue continue
}
c.Limiters = append(c.Limiters, s)
} }
cfg.Limiters = append(cfg.Limiters, s) return nil
} })
config.SetGlobal(cfg)
ctx.JSON(http.StatusOK, Response{ ctx.JSON(http.StatusOK, Response{
Msg: "OK", Msg: "OK",

View File

@ -47,9 +47,10 @@ func createRateLimiter(ctx *gin.Context) {
return return
} }
cfg := config.Global() config.OnUpdate(func(c *config.Config) error {
cfg.CLimiters = append(cfg.CLimiters, &req.Data) c.RLimiters = append(c.RLimiters, &req.Data)
config.SetGlobal(cfg) return nil
})
ctx.JSON(http.StatusOK, Response{ ctx.JSON(http.StatusOK, Response{
Msg: "OK", Msg: "OK",
@ -102,14 +103,15 @@ func updateRateLimiter(ctx *gin.Context) {
return return
} }
cfg := config.Global() config.OnUpdate(func(c *config.Config) error {
for i := range cfg.Limiters { for i := range c.RLimiters {
if cfg.Limiters[i].Name == req.Limiter { if c.RLimiters[i].Name == req.Limiter {
cfg.Limiters[i] = &req.Data c.RLimiters[i] = &req.Data
break break
}
} }
} return nil
config.SetGlobal(cfg) })
ctx.JSON(http.StatusOK, Response{ ctx.JSON(http.StatusOK, Response{
Msg: "OK", Msg: "OK",
@ -149,16 +151,17 @@ func deleteRateLimiter(ctx *gin.Context) {
} }
registry.RateLimiterRegistry().Unregister(req.Limiter) registry.RateLimiterRegistry().Unregister(req.Limiter)
cfg := config.Global() config.OnUpdate(func(c *config.Config) error {
limiteres := cfg.Limiters limiteres := c.RLimiters
cfg.Limiters = nil c.RLimiters = nil
for _, s := range limiteres { for _, s := range limiteres {
if s.Name == req.Limiter { if s.Name == req.Limiter {
continue continue
}
c.RLimiters = append(c.RLimiters, s)
} }
cfg.Limiters = append(cfg.Limiters, s) return nil
} })
config.SetGlobal(cfg)
ctx.JSON(http.StatusOK, Response{ ctx.JSON(http.StatusOK, Response{
Msg: "OK", Msg: "OK",

View File

@ -51,9 +51,10 @@ func createResolver(ctx *gin.Context) {
return return
} }
cfg := config.Global() config.OnUpdate(func(c *config.Config) error {
cfg.Resolvers = append(cfg.Resolvers, &req.Data) c.Resolvers = append(c.Resolvers, &req.Data)
config.SetGlobal(cfg) return nil
})
ctx.JSON(http.StatusOK, Response{ ctx.JSON(http.StatusOK, Response{
Msg: "OK", Msg: "OK",
@ -110,14 +111,15 @@ func updateResolver(ctx *gin.Context) {
return return
} }
cfg := config.Global() config.OnUpdate(func(c *config.Config) error {
for i := range cfg.Resolvers { for i := range c.Resolvers {
if cfg.Resolvers[i].Name == req.Resolver { if c.Resolvers[i].Name == req.Resolver {
cfg.Resolvers[i] = &req.Data c.Resolvers[i] = &req.Data
break break
}
} }
} return nil
config.SetGlobal(cfg) })
ctx.JSON(http.StatusOK, Response{ ctx.JSON(http.StatusOK, Response{
Msg: "OK", Msg: "OK",
@ -157,16 +159,17 @@ func deleteResolver(ctx *gin.Context) {
} }
registry.ResolverRegistry().Unregister(req.Resolver) registry.ResolverRegistry().Unregister(req.Resolver)
cfg := config.Global() config.OnUpdate(func(c *config.Config) error {
resolvers := cfg.Resolvers resolvers := c.Resolvers
cfg.Resolvers = nil c.Resolvers = nil
for _, s := range resolvers { for _, s := range resolvers {
if s.Name == req.Resolver { if s.Name == req.Resolver {
continue continue
}
c.Resolvers = append(c.Resolvers, s)
} }
cfg.Resolvers = append(cfg.Resolvers, s) return nil
} })
config.SetGlobal(cfg)
ctx.JSON(http.StatusOK, Response{ ctx.JSON(http.StatusOK, Response{
Msg: "OK", Msg: "OK",

View File

@ -59,9 +59,10 @@ func createService(ctx *gin.Context) {
go svc.Serve() go svc.Serve()
cfg := config.Global() config.OnUpdate(func(c *config.Config) error {
cfg.Services = append(cfg.Services, &req.Data) c.Services = append(c.Services, &req.Data)
config.SetGlobal(cfg) return nil
})
ctx.JSON(http.StatusOK, Response{ ctx.JSON(http.StatusOK, Response{
Msg: "OK", Msg: "OK",
@ -123,14 +124,15 @@ func updateService(ctx *gin.Context) {
go svc.Serve() go svc.Serve()
cfg := config.Global() config.OnUpdate(func(c *config.Config) error {
for i := range cfg.Services { for i := range c.Services {
if cfg.Services[i].Name == req.Service { if c.Services[i].Name == req.Service {
cfg.Services[i] = &req.Data c.Services[i] = &req.Data
break break
}
} }
} return nil
config.SetGlobal(cfg) })
ctx.JSON(http.StatusOK, Response{ ctx.JSON(http.StatusOK, Response{
Msg: "OK", Msg: "OK",
@ -173,16 +175,17 @@ func deleteService(ctx *gin.Context) {
registry.ServiceRegistry().Unregister(req.Service) registry.ServiceRegistry().Unregister(req.Service)
svc.Close() svc.Close()
cfg := config.Global() config.OnUpdate(func(c *config.Config) error {
services := cfg.Services services := c.Services
cfg.Services = nil c.Services = nil
for _, s := range services { for _, s := range services {
if s.Name == req.Service { if s.Name == req.Service {
continue continue
}
c.Services = append(c.Services, s)
} }
cfg.Services = append(cfg.Services, s) return nil
} })
config.SetGlobal(cfg)
ctx.JSON(http.StatusOK, Response{ ctx.JSON(http.StatusOK, Response{
Msg: "OK", Msg: "OK",

View File

@ -35,13 +35,20 @@ func Global() *Config {
return cfg return cfg
} }
func SetGlobal(c *Config) { func Set(c *Config) {
globalMux.Lock() globalMux.Lock()
defer globalMux.Unlock() defer globalMux.Unlock()
global = c global = c
} }
func OnUpdate(f func(c *Config) error) error {
globalMux.Lock()
defer globalMux.Unlock()
return f(global)
}
type LogConfig struct { type LogConfig struct {
Output string `yaml:",omitempty" json:"output,omitempty"` Output string `yaml:",omitempty" json:"output,omitempty"`
Level string `yaml:",omitempty" json:"level,omitempty"` Level string `yaml:",omitempty" json:"level,omitempty"`