Skip to content

Commit f91fa64

Browse files
committed
cluster: replace in-tree validator with go-config jsonschema
Switch tt cluster show --validate / cluster publish from the in-tree enumerated path validator to go-config jsonschema over the embedded Tarantool schema. - Add cli/cluster.Validate wrapping go-config jsonschema; drop lib/cluster/{paths,schema,validators}.go (and tests) — ~2.9k LoC. - Update cli/cluster/cmd/common_test.go to assert on the new `<path> [code] <message>` substring format. - Skip three integration tests (test_cluster_show_config_app_validate_error, test_cluster_publish_invalid_cluster, test_cluster_publish_invalid_instance) whose expected output depends on substituted {property}/{received}/{expected} placeholders; awaiting tarantool/go-config#60. - Document the behaviour change in CHANGELOG. Part of TNTP-7390
1 parent c031678 commit f91fa64

11 files changed

Lines changed: 90 additions & 2971 deletions

File tree

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,10 @@ for machine-readable output.
2525
- `lib/cluster`: removed `EnvCollector` and the generated `ConfigEnvPaths`;
2626
`cli/cluster` now loads config files and environment variables via upstream
2727
go-config.
28+
- `tt cluster show --validate` and `tt cluster publish` now validate against the embedded
29+
Tarantool JSON Schema instead of the in-tree enumerated path validator. The new validator
30+
is stricter (rejects unknown top-level / scope properties) and produces error messages in
31+
the upstream `<path> [code] <message>` format.
2832

2933
### Fixed
3034

cli/cluster/cmd/common.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ func validateRawClusterConfig(config *libcluster.Config) error {
9797
// validateClusterConfig validates a cluster configuration.
9898
func validateClusterConfig(cconfig libcluster.ClusterConfig, full bool) error {
9999
var errs []error
100-
if err := libcluster.Validate(cconfig.RawConfig, libcluster.TarantoolSchema); err != nil {
100+
if err := cluster.Validate(cconfig.RawConfig); err != nil {
101101
err = fmt.Errorf("an invalid cluster configuration: %s", err)
102102
errs = append(errs, err)
103103
}
@@ -123,7 +123,7 @@ func validateClusterConfig(cconfig libcluster.ClusterConfig, full bool) error {
123123

124124
// validateInstanceConfig validates an instance configuration.
125125
func validateInstanceConfig(config *libcluster.Config, name string) error {
126-
if err := libcluster.Validate(config, libcluster.TarantoolSchema); err != nil {
126+
if err := cluster.Validate(config); err != nil {
127127
return fmt.Errorf("an invalid instance %q configuration: %w", name, err)
128128
}
129129
return nil

cli/cluster/cmd/common_test.go

Lines changed: 17 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,10 @@ groups:
5151
foo: bar
5252
`),
5353
Full: []bool{false, true},
54-
Err: nil,
54+
Err: []string{
55+
"an invalid cluster configuration: ",
56+
"foo [schema] No values are allowed because the schema is set to 'false'",
57+
},
5558
},
5659
{
5760
Name: "valid fields",
@@ -91,9 +94,8 @@ groups:
9194
nonblock: true
9295
`),
9396
Full: []bool{false, true},
94-
Err: []string{"an invalid cluster configuration: " +
95-
"invalid path \"audit_log.nonblock\": " +
96-
"unexpected value \"123\" of type int, expected boolean"},
97+
Err: []string{"an invalid cluster configuration: ",
98+
"audit_log/nonblock [type] invalid type"},
9799
},
98100
{
99101
Name: "invalid group",
@@ -109,9 +111,8 @@ groups:
109111
c:
110112
`),
111113
Full: []bool{false, true},
112-
Err: []string{"an invalid instance \"c\" configuration: " +
113-
"invalid path \"audit_log.nonblock\": " +
114-
"unexpected value \"123\" of type int, expected boolean"},
114+
Err: []string{"an invalid instance \"c\" configuration: ",
115+
"audit_log/nonblock [type] invalid type"},
115116
},
116117
{
117118
Name: "invalid replicaset",
@@ -129,9 +130,8 @@ groups:
129130
c:
130131
`),
131132
Full: []bool{false, true},
132-
Err: []string{"an invalid instance \"c\" configuration: " +
133-
"invalid path \"audit_log.nonblock\": " +
134-
"unexpected value \"123\" of type int, expected boolean"},
133+
Err: []string{"an invalid instance \"c\" configuration: ",
134+
"audit_log/nonblock [type] invalid type"},
135135
},
136136
{
137137
Name: "invalid instance",
@@ -151,9 +151,8 @@ groups:
151151
nonblock: 123
152152
`),
153153
Full: []bool{false, true},
154-
Err: []string{"an invalid instance \"c\" configuration: " +
155-
"invalid path \"audit_log.nonblock\": " +
156-
"unexpected value \"123\" of type int, expected boolean"},
154+
Err: []string{"an invalid instance \"c\" configuration: ",
155+
"audit_log/nonblock [type] invalid type"},
157156
},
158157
{
159158
Name: "invalid instances",
@@ -177,12 +176,9 @@ groups:
177176
`),
178177
Full: []bool{false, true},
179178
Err: []string{
180-
"an invalid instance \"c1\" configuration: " +
181-
"invalid path \"audit_log.nonblock\": " +
182-
"unexpected value \"123\" of type int, expected boolean",
183-
"an invalid instance \"c2\" configuration: " +
184-
"invalid path \"audit_log.nonblock\": " +
185-
"unexpected value \"123\" of type int, expected boolean",
179+
"an invalid instance \"c1\" configuration: ",
180+
"an invalid instance \"c2\" configuration: ",
181+
"audit_log/nonblock [type] invalid type",
186182
},
187183
},
188184
{
@@ -229,9 +225,8 @@ groups:
229225
nonblock: true
230226
`),
231227
Full: []bool{true},
232-
Err: []string{"an invalid instance \"c\" configuration: " +
233-
"invalid path \"audit_log.nonblock\": " +
234-
"unexpected value \"123\" of type string, expected boolean"},
228+
Err: []string{"an invalid instance \"c\" configuration: ",
229+
"audit_log/nonblock [type] invalid type"},
235230
},
236231
}
237232

cli/cluster/validate.go

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
package cluster
2+
3+
import (
4+
"bytes"
5+
"errors"
6+
"fmt"
7+
8+
"github.com/tarantool/go-config/collectors"
9+
gcttarantool "github.com/tarantool/go-config/tarantool"
10+
"github.com/tarantool/go-config/validators/jsonschema"
11+
libcluster "github.com/tarantool/tt/lib/cluster"
12+
)
13+
14+
// Validate validates a configuration against the embedded JSON Schema for the
15+
// newest known Tarantool version.
16+
func Validate(config *libcluster.Config) error {
17+
yamlBytes := []byte(config.String())
18+
if len(bytes.TrimSpace(yamlBytes)) == 0 {
19+
return nil
20+
}
21+
22+
versions := gcttarantool.SchemaVersions()
23+
if len(versions) == 0 {
24+
return fmt.Errorf("no Tarantool schemas registered")
25+
}
26+
newest := versions[len(versions)-1]
27+
schemaBytes, ok := gcttarantool.Schema(newest)
28+
if !ok {
29+
return fmt.Errorf("schema for Tarantool version %q not found", newest)
30+
}
31+
32+
validator, err := jsonschema.New(schemaBytes)
33+
if err != nil {
34+
return fmt.Errorf("failed to compile schema: %w", err)
35+
}
36+
37+
node, err := collectors.NewYamlFormat().From(bytes.NewReader(yamlBytes)).Parse()
38+
if err != nil {
39+
return fmt.Errorf("failed to parse config: %w", err)
40+
}
41+
42+
valErrs := validator.Validate(node)
43+
if len(valErrs) == 0 {
44+
return nil
45+
}
46+
47+
errs := make([]error, len(valErrs))
48+
for i := range valErrs {
49+
errs[i] = &valErrs[i]
50+
}
51+
return errors.Join(errs...)
52+
}

0 commit comments

Comments
 (0)