Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add trace value in unwinding parent catalogs #454

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
80 changes: 77 additions & 3 deletions api/pkg/apis/v1alpha1/managers/configs/configs-manager_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -539,7 +539,6 @@ func TestCircularCatalogReferences(t *testing.T) {
os.Setenv(constants.SymphonyAPIUrlEnvName, ts.URL+"/")
os.Setenv(constants.UseServiceAccountTokenEnvName, "false")

// TODO: here evalContext shares the same copy as in Get
evalContext := utils.EvaluationContext{}
vendorContext := coa_contexts.VendorContext{
EvaluationContext: &evalContext,
Expand Down Expand Up @@ -575,7 +574,82 @@ func TestCircularCatalogReferences(t *testing.T) {

_, err = manager.Get("config2:v1", "attribute", nil, evalContext)
assert.Nil(t, err, "Detect correct attribute, expect no error")
}

func TestParentConfigEvaluation(t *testing.T) {
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
var response interface{}
switch r.URL.Path {
case "/catalogs/registry/config-v-v1":
response = model.CatalogState{
ObjectMeta: model.ObjectMeta{
Name: "config-v-v1",
},
Spec: &model.CatalogSpec{
ParentName: "parent:v1",
Properties: map[string]interface{}{
"attribute": "value",
},
},
}
case "/catalogs/registry/parent-v-v1":
response = model.CatalogState{
ObjectMeta: model.ObjectMeta{
Name: "parent-v-v1",
},
Spec: &model.CatalogSpec{
Properties: map[string]interface{}{
"parentAttribute": "${{$config('config:v1','attribute')}}",
"parentCircular": "${{$config('config:v1','parentCircular')}}",
},
},
}
default:
response = AuthResponse{
AccessToken: "test-token",
TokenType: "Bearer",
Username: "test-user",
Roles: []string{"role1", "role2"},
}
}

json.NewEncoder(w).Encode(response)
}))
defer ts.Close()
os.Setenv(constants.SymphonyAPIUrlEnvName, ts.URL+"/")
os.Setenv(constants.UseServiceAccountTokenEnvName, "false")

evalContext := utils.EvaluationContext{}
vendorContext := coa_contexts.VendorContext{
EvaluationContext: &evalContext,
}
provider := catalog.CatalogConfigProvider{}

provider.Context = &coa_contexts.ManagerContext{
VencorContext: &vendorContext,
}
err := provider.Init(catalog.CatalogConfigProviderConfig{})
assert.Nil(t, err)

manager := ConfigsManager{}
config := managers.ManagerConfig{
Name: "config-name",
Type: "config-type",
Properties: map[string]string{
"providers.config": "ConfigProvider",
},
}
providers := make(map[string]providers.IProvider)
providers["ConfigProvider"] = &provider
err = manager.Init(&vendorContext, config, providers)
assert.Nil(t, err)

evalContext.ConfigProvider = &manager

val, err := manager.Get("config:v1", "parentAttribute", nil, evalContext)
assert.Equal(t, "value", val)
assert.Nil(t, err)

_, err = manager.Get("config1:v1", "parentAttribute", nil, evalContext)
assert.Error(t, err, "Detect circular dependency, override: parent-v-v1, field: parentAttribute")
_, err = manager.Get("config:v1", "parentCircular", nil, evalContext)
assert.Error(t, err, "Circular dependency in config should throw error")
}
34 changes: 15 additions & 19 deletions api/pkg/apis/v1alpha1/providers/config/catalog/catalogprovider.go
Original file line number Diff line number Diff line change
Expand Up @@ -91,21 +91,17 @@ func CatalogConfigProviderConfigFromMap(properties map[string]string) (CatalogCo
return ret, nil
}

func (m *CatalogConfigProvider) unwindOverrides(ctx context.Context, override string, field string, namespace string) (string, error) {
func (m *CatalogConfigProvider) unwindOverrides(ctx context.Context, override string, field string, namespace string, localcontext interface{}, dependencyList map[string]map[string]bool) (interface{}, error) {
override = utils.ConvertReferenceToObjectName(override)
catalog, err := m.ApiClient.GetCatalog(ctx, override, namespace, m.Config.User, m.Config.Password)
if err != nil {
return "", err
}
if v, ok := catalog.Spec.Properties[field]; ok {
if vstring, ok := v.(string); ok {
return vstring, nil
} else {
return "", v1alpha2.NewCOAError(nil, fmt.Sprintf("field '%s' doesn't has a valid value in configuration'%s'", field, override), v1alpha2.BadConfig)
}
return m.traceValue(v, localcontext, dependencyList)
}
if catalog.Spec.ParentName != "" {
return m.unwindOverrides(ctx, catalog.Spec.ParentName, field, namespace)
return m.unwindOverrides(ctx, catalog.Spec.ParentName, field, namespace, localcontext, dependencyList)
}
return "", v1alpha2.NewCOAError(nil, fmt.Sprintf("field '%s' is not found in configuration '%s'", field, override), v1alpha2.NotFound)
}
Expand All @@ -125,25 +121,25 @@ func (m *CatalogConfigProvider) Read(ctx context.Context, object string, field s
return "", err
}

if v, ok := catalog.Spec.Properties[field]; ok {
// check circular dependency
var dependencyList map[string]map[string]bool = nil
if localcontext != nil {
if evalContext, ok := localcontext.(coa_utils.EvaluationContext); ok {
if coa_utils.HasCircularDependency(object, field, evalContext) {
clog.Errorf(" M (Catalog): Read detect circular dependency. Object: %v, field: %v, ", object, field)
return "", v1alpha2.NewCOAError(nil, fmt.Sprintf("Detect circular dependency, object: %s, field: %s", object, field), v1alpha2.BadConfig)
}
dependencyList = coa_utils.DeepCopyDependencyList(evalContext.ParentConfigs)
dependencyList = coa_utils.UpdateDependencyList(object, field, dependencyList)
// check circular dependency
var dependencyList map[string]map[string]bool = nil
if localcontext != nil {
if evalContext, ok := localcontext.(coa_utils.EvaluationContext); ok {
if coa_utils.HasCircularDependency(object, field, evalContext) {
clog.Errorf(" M (Catalog): Read detect circular dependency. Object: %v, field: %v, ", object, field)
return "", v1alpha2.NewCOAError(nil, fmt.Sprintf("Detect circular dependency, object: %s, field: %s", object, field), v1alpha2.BadConfig)
}
dependencyList = coa_utils.DeepCopyDependencyList(evalContext.ParentConfigs)
dependencyList = coa_utils.UpdateDependencyList(object, field, dependencyList)
}
}

if v, ok := catalog.Spec.Properties[field]; ok {
return m.traceValue(v, localcontext, dependencyList)
}

if catalog.Spec.ParentName != "" {
overrid, err := m.unwindOverrides(ctx, catalog.Spec.ParentName, field, namespace)
overrid, err := m.unwindOverrides(ctx, catalog.Spec.ParentName, field, namespace, localcontext, dependencyList)
if err != nil {
return "", err
} else {
Expand Down
Loading