in pkg/apisix/utils.go [45:247]
func skipRequest[T ResourceTypes](cluster *cluster, shouldCompare bool, url, id string, obj T) (T, bool) {
if cluster.syncComparison && shouldCompare {
var generatedObj T
resourceType := ""
// GlobalRule and Consumer has Plugins field which type will mismatch in DeepEqual
switch (interface{})(generatedObj).(type) {
case *v1.GlobalRule:
generatedObj = obj
resourceType = "global_rule"
case *v1.Consumer:
generatedObj = obj
resourceType = "consumer"
}
if generatedObj == nil {
generatedObj = obj
} else {
j, err := json.Marshal(generatedObj)
if err != nil {
log.Debugw("sync comparison continue operation",
zap.String("reason", "failed to marshal object"),
zap.Error(err),
zap.Any("resource", resourceType),
zap.Any("obj", generatedObj),
)
return nil, false
}
err = json.Unmarshal(j, &generatedObj)
if err != nil {
log.Debugw("sync comparison continue operation",
zap.String("reason", "failed to unmarshal object"),
zap.Error(err),
zap.Any("resource", resourceType),
zap.Any("json", j),
)
return nil, false
}
}
var (
// generated object may be different from server response object,
// so we need another cache to store generated objs
cachedGeneratedObj interface{}
err error
)
// type-switch on parametric types is not implemented yet
switch (interface{})(generatedObj).(type) {
case *v1.Route:
cachedGeneratedObj, err = cluster.generatedObjCache.GetRoute(id)
resourceType = "route"
case *v1.Ssl:
cachedGeneratedObj, err = cluster.generatedObjCache.GetSSL(id)
resourceType = "ssl"
case *v1.Upstream:
cachedGeneratedObj, err = cluster.generatedObjCache.GetUpstream(id)
resourceType = "upstream"
case *v1.StreamRoute:
cachedGeneratedObj, err = cluster.generatedObjCache.GetStreamRoute(id)
resourceType = "stream_route"
case *v1.GlobalRule:
cachedGeneratedObj, err = cluster.generatedObjCache.GetGlobalRule(id)
resourceType = "global_rule"
case *v1.Consumer:
cachedGeneratedObj, err = cluster.generatedObjCache.GetConsumer(id)
resourceType = "consumer"
case *v1.PluginConfig:
cachedGeneratedObj, err = cluster.generatedObjCache.GetPluginConfig(id)
resourceType = "plugin_config"
//case *v1.PluginMetadata:
default:
log.Errorw("resource comparison aborted",
zap.Error(ErrUnknownApisixResourceType),
zap.Any("obj", generatedObj),
)
return nil, false
}
if err == nil && cachedGeneratedObj != nil {
if reflect.DeepEqual(cachedGeneratedObj, generatedObj) {
var (
expectedServerObj interface{}
)
switch (interface{})(generatedObj).(type) {
case *v1.Route:
expectedServerObj, err = cluster.cache.GetRoute(id)
case *v1.Ssl:
expectedServerObj, err = cluster.cache.GetSSL(id)
if err == nil {
expectedServerObj.(*v1.Ssl).Key = ""
}
case *v1.Upstream:
expectedServerObj, err = cluster.cache.GetUpstream(id)
case *v1.StreamRoute:
expectedServerObj, err = cluster.cache.GetStreamRoute(id)
case *v1.GlobalRule:
expectedServerObj, err = cluster.cache.GetGlobalRule(id)
case *v1.Consumer:
expectedServerObj, err = cluster.cache.GetConsumer(id)
case *v1.PluginConfig:
expectedServerObj, err = cluster.cache.GetPluginConfig(id)
}
if err == nil && expectedServerObj != nil {
// Now we have the expected server obj, compare to actual object in APISIX
var (
serverObj interface{}
)
switch (interface{})(generatedObj).(type) {
case *v1.Route:
serverObj, err = cluster.GetRoute(context.Background(), url, id)
case *v1.Ssl:
serverObj, err = cluster.GetSSL(context.Background(), url, id)
case *v1.Upstream:
serverObj, err = cluster.GetUpstream(context.Background(), url, id)
case *v1.StreamRoute:
serverObj, err = cluster.GetStreamRoute(context.Background(), url, id)
case *v1.GlobalRule:
serverObj, err = cluster.GetGlobalRule(context.Background(), url, id)
case *v1.Consumer:
serverObj, err = cluster.GetConsumer(context.Background(), url, id)
case *v1.PluginConfig:
serverObj, err = cluster.GetPluginConfig(context.Background(), url, id)
}
if err == nil && serverObj != nil {
if reflect.DeepEqual(expectedServerObj, serverObj) {
log.Debugw("sync comparison skipped same resource",
zap.String("reason", "equal"),
zap.String("resource", resourceType),
zap.Any("obj", generatedObj),
zap.Any("cached", cachedGeneratedObj),
)
return expectedServerObj.(T), true
}
log.Debugw("sync comparison continue operation",
zap.String("reason", "cached server object doesn't match APISIX object"),
zap.String("resource", resourceType),
zap.Error(err),
zap.String("id", id),
zap.Any("cached_obj", expectedServerObj),
zap.Any("server_obj", serverObj),
)
return nil, false
}
log.Debugw("sync comparison continue operation",
zap.String("reason", "failed to get object from APISIX"),
zap.String("resource", resourceType),
zap.Error(err),
zap.String("id", id),
)
return nil, false
}
log.Debugw("sync comparison continue operation",
zap.String("reason", "failed to get cached server object"),
zap.String("resource", resourceType),
zap.Error(err),
zap.String("id", id),
)
return nil, false
}
log.Debugw("sync comparison continue operation",
zap.String("reason", "controller generated object doesn't match"),
zap.String("resource", resourceType),
zap.Any("obj", generatedObj),
zap.Any("cached", cachedGeneratedObj),
)
return nil, false
} else if err == cache.ErrNotFound {
log.Debugw("sync comparison continue operation",
zap.String("reason", "not in cache"),
zap.String("resource", resourceType),
zap.String("id", id),
zap.Any("obj", generatedObj),
zap.Any("cached", cachedGeneratedObj),
)
return nil, false
} else {
log.Debugw("sync comparison continue operation",
zap.Error(err),
zap.String("reason", "failed to get cached generated object"),
zap.String("resource", resourceType),
zap.String("id", id),
zap.Any("obj", generatedObj),
zap.Any("cached", cachedGeneratedObj),
)
return nil, false
}
}
return nil, false
}