From e3f2124b5844435bef76887ee015e10387406ef5 Mon Sep 17 00:00:00 2001 From: kklimonda-cl Date: Thu, 8 Aug 2024 15:40:24 +0200 Subject: [PATCH] feat: update schema specification with JSON schema validation (#122) A new schema for API specifications, along with JSON schema files that can be used to validate specification, and runtime conversion of new schema to the old one to avoid large changes across our codegen templates. --- go.mod | 12 +- go.sum | 26 +- pkg/errors/errors.go | 46 ++ pkg/properties/normalized.go | 368 ++++++++- pkg/properties/normalized_test.go | 489 +----------- pkg/schema/imports/import.go | 9 + pkg/schema/location/location.go | 21 + pkg/schema/object/object.go | 59 ++ pkg/schema/object/object_suite_test.go | 15 + pkg/schema/parameter/parameter.go | 185 +++++ pkg/schema/parameter/parameter_suite_test.go | 13 + pkg/schema/parameter/parameter_test.go | 81 ++ pkg/schema/profile/profile.go | 16 + pkg/schema/validator/validators.go | 101 +++ pkg/schema/xpath/xpath.go | 57 ++ pkg/schema/xpath/xpath_suite_test.go | 19 + pkg/schema/xpath/xpath_test.go | 34 + pkg/translate/structs.go | 6 +- pkg/translate/structs_test.go | 54 +- pkg/version/version.go | 146 +++- pkg/version/version_suite_test.go | 15 + pkg/version/version_test.go | 181 +++-- specs/device/dns.yaml | 188 ++--- specs/device/ntp.yaml | 261 ++++--- specs/network/interface/ethernet.yaml | 317 ++++---- specs/network/interface/loopback.yaml | 252 +++--- .../interface-management-profile.yaml | 195 ++--- specs/network/virtual-router.yaml | 636 ++++++++------- specs/network/zone.yaml | 349 +++++---- specs/objects/address-group.yaml | 249 +++--- specs/objects/address.yaml | 262 ++++--- specs/objects/service-group.yaml | 235 +++--- specs/objects/service.yaml | 350 +++++---- specs/objects/tag.yaml | 383 ++++----- specs/panorama/device-group.yaml | 96 +-- specs/panorama/template-stack.yaml | 103 +-- specs/panorama/template.yaml | 152 ++-- specs/policies/security-policy-rule.yaml | 724 ++++++++++-------- specs/schema/import.schema.json | 15 + specs/schema/location.schema.json | 29 + specs/schema/object.schema.json | 80 ++ specs/schema/profile.schema.json | 13 + specs/schema/schema.json | 31 + specs/schema/spec.schema.json | 121 +++ specs/schema/validator.schema.json | 65 ++ specs/schema/xpath.schema.json | 41 + 46 files changed, 4343 insertions(+), 2757 deletions(-) create mode 100644 pkg/errors/errors.go create mode 100644 pkg/schema/imports/import.go create mode 100644 pkg/schema/location/location.go create mode 100644 pkg/schema/object/object.go create mode 100644 pkg/schema/object/object_suite_test.go create mode 100644 pkg/schema/parameter/parameter.go create mode 100644 pkg/schema/parameter/parameter_suite_test.go create mode 100644 pkg/schema/parameter/parameter_test.go create mode 100644 pkg/schema/profile/profile.go create mode 100644 pkg/schema/validator/validators.go create mode 100644 pkg/schema/xpath/xpath.go create mode 100644 pkg/schema/xpath/xpath_suite_test.go create mode 100644 pkg/schema/xpath/xpath_test.go create mode 100644 pkg/version/version_suite_test.go create mode 100644 specs/schema/import.schema.json create mode 100644 specs/schema/location.schema.json create mode 100644 specs/schema/object.schema.json create mode 100644 specs/schema/profile.schema.json create mode 100644 specs/schema/schema.json create mode 100644 specs/schema/spec.schema.json create mode 100644 specs/schema/validator.schema.json create mode 100644 specs/schema/xpath.schema.json diff --git a/go.mod b/go.mod index 4e301715..fc4c4514 100644 --- a/go.mod +++ b/go.mod @@ -1,14 +1,24 @@ module github.com/paloaltonetworks/pan-os-codegen require ( + github.com/onsi/ginkgo/v2 v2.20.0 + github.com/onsi/gomega v1.34.1 github.com/stretchr/testify v1.9.0 - golang.org/x/text v0.16.0 + golang.org/x/text v0.17.0 gopkg.in/yaml.v3 v3.0.1 ) require ( github.com/davecgh/go-spew v1.1.1 // indirect + github.com/go-logr/logr v1.4.2 // indirect + github.com/go-task/slim-sprig/v3 v3.0.0 // indirect + github.com/google/go-cmp v0.6.0 // indirect + github.com/google/pprof v0.0.0-20240727154555-813a5fbdbec8 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect + golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 // indirect + golang.org/x/net v0.28.0 // indirect + golang.org/x/sys v0.23.0 // indirect + golang.org/x/tools v0.24.0 // indirect ) go 1.22.5 diff --git a/go.sum b/go.sum index 5474e7a4..34f9c99b 100644 --- a/go.sum +++ b/go.sum @@ -1,11 +1,33 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= +github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI= +github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/pprof v0.0.0-20240727154555-813a5fbdbec8 h1:FKHo8hFI3A+7w0aUQuYXQ+6EN5stWmeY/AZqtM8xk9k= +github.com/google/pprof v0.0.0-20240727154555-813a5fbdbec8/go.mod h1:K1liHPHnj73Fdn/EKuT8nrFqBihUSKXoLYU0BuatOYo= +github.com/onsi/ginkgo/v2 v2.20.0 h1:PE84V2mHqoT1sglvHc8ZdQtPcwmvvt29WLEEO3xmdZw= +github.com/onsi/ginkgo/v2 v2.20.0/go.mod h1:lG9ey2Z29hR41WMVthyJBGUBcBhGOtoPF2VFMvBXFCI= +github.com/onsi/gomega v1.34.1 h1:EUMJIKUjM8sKjYbtxQI9A4z2o+rruxnzNvpknOXie6k= +github.com/onsi/gomega v1.34.1/go.mod h1:kU1QgUvBDLXBJq618Xvm2LUX6rSAfRaFRTcdOeDLwwY= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= -golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4= -golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI= +golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 h1:2dVuKD2vS7b0QIHQbpyTISPd0LeHDbnYEryqj5Q1ug8= +golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY= +golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE= +golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg= +golang.org/x/sys v0.23.0 h1:YfKFowiIMvtgl1UERQoTPPToxltDeZfbj4H7dVUCwmM= +golang.org/x/sys v0.23.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/text v0.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc= +golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= +golang.org/x/tools v0.24.0 h1:J1shsA93PJUEVaUSaay7UXAyE8aimq3GW0pjlolpa24= +golang.org/x/tools v0.24.0/go.mod h1:YhNqVBIfWHdzvTLs0d8LCuMhkKUgSUKldakyV7W/WDQ= +google.golang.org/protobuf v1.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg= +google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= diff --git a/pkg/errors/errors.go b/pkg/errors/errors.go new file mode 100644 index 00000000..5351c797 --- /dev/null +++ b/pkg/errors/errors.go @@ -0,0 +1,46 @@ +package errors + +import "fmt" + +type SchemaError struct { + Message string + Err error +} + +func NewSchemaError(msg string) *SchemaError { + return &SchemaError{Message: msg} +} + +func (o *SchemaError) Error() string { + return o.Message +} + +func (o *SchemaError) Unwrap() error { + return o.Err +} + +type MarshallerError struct { + Err error + Message string +} + +func NewMarshallerError(msg string) *MarshallerError { + return &MarshallerError{Message: msg} +} + +func NewWrappedMarshallerError(err error) *MarshallerError { + return &MarshallerError{ + Err: err, + } +} + +func (o *MarshallerError) Error() string { + if o.Err != nil { + return fmt.Sprintf("error while marshalling specs: %s", o.Err) + } + return o.Message +} + +func (o *MarshallerError) Unwrap() error { + return o.Err +} diff --git a/pkg/properties/normalized.go b/pkg/properties/normalized.go index 1d21b824..237973dc 100644 --- a/pkg/properties/normalized.go +++ b/pkg/properties/normalized.go @@ -9,6 +9,10 @@ import ( "github.com/paloaltonetworks/pan-os-codegen/pkg/content" "github.com/paloaltonetworks/pan-os-codegen/pkg/naming" + "github.com/paloaltonetworks/pan-os-codegen/pkg/schema/object" + "github.com/paloaltonetworks/pan-os-codegen/pkg/schema/parameter" + "github.com/paloaltonetworks/pan-os-codegen/pkg/schema/validator" + "github.com/paloaltonetworks/pan-os-codegen/pkg/schema/xpath" ) type Normalization struct { @@ -238,11 +242,369 @@ func GetNormalizations() ([]string, error) { return files, nil } +func schemaParameterToSpecParameter(schemaSpec *parameter.Parameter) (*SpecParam, error) { + var specType string + if schemaSpec.Type == "object" { + specType = "" + } else if schemaSpec.Type == "enum" { + specType = "string" + } else { + specType = schemaSpec.Type + } + + var defaultVal string + + var innerSpec *Spec + var itemsSpec SpecParamItems + + generateInnerSpec := func(spec *parameter.StructSpec) (*Spec, error) { + params := make(map[string]*SpecParam) + oneofs := make(map[string]*SpecParam) + + for _, elt := range spec.Parameters { + param, err := schemaParameterToSpecParameter(elt) + if err != nil { + return nil, err + } + params[elt.Name] = param + } + + for _, elt := range spec.Variants { + param, err := schemaParameterToSpecParameter(elt) + if err != nil { + return nil, err + } + oneofs[elt.Name] = param + } + + return &Spec{ + Params: params, + OneOf: oneofs, + }, nil + } + + switch spec := schemaSpec.Spec.(type) { + case *parameter.StructSpec: + var err error + innerSpec, err = generateInnerSpec(spec) + if err != nil { + return nil, err + } + + case *parameter.ListSpec: + if spec.Items.Type == "object" { + itemsSpec.Type = "entry" + var err error + innerSpec, err = generateInnerSpec(&spec.Items.Spec) + if err != nil { + return nil, err + } + } else { + itemsSpec.Type = spec.Items.Type + } + for _, v := range schemaSpec.Validators { + switch spec := v.Spec.(type) { + case *validator.CountSpec: + min := int64(spec.Min) + max := int64(spec.Max) + itemsSpec.Length = &SpecParamItemsLength{ + Min: &min, + Max: &max, + } + } + } + case *parameter.EnumSpec: + defaultVal = spec.Default + case *parameter.NilSpec: + specType = "string" + case *parameter.SimpleSpec: + if typed, ok := spec.Default.(string); ok { + defaultVal = typed + } + } + + var profiles []*SpecParamProfile + for _, profile := range schemaSpec.Profiles { + var notPresent bool + var version string + if profile.MaximumVersion != nil { + notPresent = true + version = profile.MaximumVersion.String() + } else if profile.MinimumVersion != nil { + version = profile.MinimumVersion.String() + } + profiles = append(profiles, &SpecParamProfile{ + Xpath: profile.Xpath, + Type: profile.Type, + NotPresent: notPresent, + FromVersion: version, + }) + } + + specParameter := &SpecParam{ + Description: schemaSpec.Description, + Type: specType, + Default: defaultVal, + Required: schemaSpec.Required, + Profiles: profiles, + Spec: innerSpec, + } + + for _, v := range schemaSpec.Validators { + switch spec := v.Spec.(type) { + case *validator.RegexpSpec: + specParameter.Regex = spec.Expr + case *validator.StringLengthSpec: + min := int64(spec.Min) + max := int64(spec.Max) + specParameter.Length = &SpecParamLength{ + Min: &min, + Max: &max, + } + case *validator.CountSpec: + min := int64(spec.Min) + max := int64(spec.Max) + specParameter.Count = &SpecParamCount{ + Min: &min, + Max: &max, + } + } + } + + if schemaSpec.Type == "list" { + specParameter.Items = &itemsSpec + } + + return specParameter, nil +} + +func generateXpathVariables(variables []xpathschema.Variable) map[string]*LocationVar { + xpathVars := make(map[string]*LocationVar) + for _, variable := range variables { + entry := &LocationVar{ + Description: variable.Description, + Default: variable.Default, + Required: variable.Required, + Validation: nil, + } + + for _, v := range variable.Validators { + switch spec := v.Spec.(type) { + case *validator.NotValuesSpec: + notValues := make(map[string]string) + for _, value := range spec.Values { + notValues[value.Value] = value.Error + + } + entry.Validation = &LocationVarValidation{ + NotValues: notValues, + } + + } + } + + xpathVars[variable.Name] = entry + } + + return xpathVars +} + +func generateImportVariables(variables []xpathschema.Variable) map[string]*ImportVar { + importVars := make(map[string]*ImportVar) + for _, variable := range variables { + entry := &ImportVar{ + Description: variable.Description, + Default: variable.Default, + } + importVars[variable.Name] = entry + } + + return importVars +} + +func schemaToSpec(object object.Object) (*Normalization, error) { + spec := &Normalization{ + Name: object.DisplayName, + TerraformProviderConfig: TerraformProviderConfig{ + SkipResource: object.TerraformConfig.SkipResource, + SkipDatasource: object.TerraformConfig.SkipDatasource, + SkipDatasourceListing: object.TerraformConfig.SkipdatasourceListing, + Suffix: object.TerraformConfig.Suffix, + }, + Locations: make(map[string]*Location), + Imports: make(map[string]*Import), + GoSdkPath: object.GoSdkConfig.Package, + XpathSuffix: object.XpathSuffix, + Version: object.Version, + Spec: &Spec{ + Params: make(map[string]*SpecParam), + OneOf: make(map[string]*SpecParam), + }, + } + + for _, location := range object.Locations { + var xpath []string + + schemaXpathVars := make(map[string]xpathschema.Variable) + for _, elt := range location.Xpath.Variables { + schemaXpathVars[elt.Name] = elt + } + for _, elt := range location.Xpath.Elements { + var eltEntry string + if xpathVar, ok := schemaXpathVars[elt[1:]]; ok { + if xpathVar.Type == "entry" { + eltEntry = fmt.Sprintf("{{ Entry %s }}", elt) + } else if xpathVar.Type == "object" { + eltEntry = fmt.Sprintf("{{ Object %s }}", elt) + } + } else { + if strings.HasPrefix(elt, "$") { + panic(fmt.Sprintf("elt: %s", elt)) + } + eltEntry = elt + } + xpath = append(xpath, eltEntry) + } + + locationDevice := &LocationDevice{} + + for _, device := range location.Devices { + if device == "panorama" { + locationDevice.Panorama = true + } else if device == "ngfw" { + locationDevice.Ngfw = true + } + } + + xpathVars := generateXpathVariables(location.Xpath.Variables) + if len(xpathVars) == 0 { + xpathVars = nil + } + + entry := &Location{ + Description: location.Description, + Device: locationDevice, + Xpath: xpath, + Vars: xpathVars, + } + spec.Locations[location.Name] = entry + } + + for _, entry := range object.Entries { + if entry.Name == "name" { + specEntry := &Entry{ + Name: &EntryName{ + Description: entry.Description, + }, + } + + for _, v := range entry.Validators { + switch spec := v.Spec.(type) { + case *validator.StringLengthSpec: + min := int64(spec.Min) + max := int64(spec.Max) + specEntry.Name.Length = &EntryNameLength{ + Min: &min, + Max: &max, + } + } + } + spec.Entry = specEntry + } + + } + + imports := make(map[string]*Import, len(object.Imports)) + for _, elt := range object.Imports { + var xpath []string + + schemaXpathVars := make(map[string]xpathschema.Variable) + for _, xpathVariable := range elt.Xpath.Variables { + schemaXpathVars[xpathVariable.Name] = xpathVariable + } + + for _, element := range elt.Xpath.Elements { + var eltEntry string + if xpathVar, ok := schemaXpathVars[element[1:]]; ok { + if xpathVar.Type == "entry" { + eltEntry = fmt.Sprintf("{{ Entry %s }}", elt.Name) + } else if xpathVar.Type == "object" { + eltEntry = fmt.Sprintf("{{ Object %s }}", elt.Name) + } + } else { + eltEntry = element + } + xpath = append(xpath, eltEntry) + } + + importVariables := generateImportVariables(elt.Xpath.Variables) + if len(importVariables) == 0 { + importVariables = nil + } + + imports[elt.Name] = &Import{ + Xpath: xpath, + Vars: importVariables, + OnlyForParams: elt.OnlyForParams, + } + } + + if len(imports) > 0 { + spec.Imports = imports + } + + consts := make(map[string]*Const) + for _, param := range object.Spec.Parameters { + specParam, err := schemaParameterToSpecParameter(param) + if err != nil { + return nil, err + } + + switch spec := param.Spec.(type) { + case *parameter.EnumSpec: + constValues := make(map[string]*ConstValue) + for _, elt := range spec.Values { + if elt.Const == "" { + continue + } + constValues[elt.Const] = &ConstValue{ + Value: elt.Value, + } + } + if len(constValues) > 0 { + consts[param.Name] = &Const{ + Values: constValues, + } + } + + } + spec.Spec.Params[param.Name] = specParam + } + + if len(consts) > 0 { + spec.Const = consts + } + + for _, param := range object.Spec.Variants { + specParam, err := schemaParameterToSpecParameter(param) + if err != nil { + return nil, err + } + spec.Spec.OneOf[param.Name] = specParam + } + + return spec, nil +} + // ParseSpec parse single spec (unmarshal file), add name variants for locations and params, add default types for params. func ParseSpec(input []byte) (*Normalization, error) { - var spec Normalization + var object object.Object + err := content.Unmarshal(input, &object) + if err != nil { + return nil, err + } - err := content.Unmarshal(input, &spec) + spec, err := schemaToSpec(object) if err != nil { return nil, err } @@ -272,7 +634,7 @@ func ParseSpec(input []byte) (*Normalization, error) { return nil, err } - return &spec, err + return spec, err } // AddNameVariantsForLocation add name variants for location (under_score and CamelCase). diff --git a/pkg/properties/normalized_test.go b/pkg/properties/normalized_test.go index b375c436..b256f1dd 100644 --- a/pkg/properties/normalized_test.go +++ b/pkg/properties/normalized_test.go @@ -1,168 +1,22 @@ package properties import ( + "os" "testing" "github.com/stretchr/testify/assert" "gopkg.in/yaml.v3" ) -const sampleSpec = `name: 'Address' -terraform_provider_config: - suffix: 'address' -go_sdk_path: - - 'objects' - - 'address' -xpath_suffix: - - 'address' -locations: - 'shared': - description: 'Located in shared.' - device: - panorama: true - ngfw: true - xpath: ['config', 'shared'] - 'from_panorama': - description: 'Located in the config pushed from Panorama.' - read_only: true - device: - ngfw: true - xpath: ['config', 'panorama'] - 'vsys': - description: 'Located in a specific vsys.' - device: - panorama: true - ngfw: true - xpath: - - 'config' - - 'devices' - - '{{ Entry $ngfw_device }}' - - 'vsys' - - '{{ Entry $vsys }}' - vars: - 'ngfw_device': - description: 'The NGFW device.' - default: 'localhost.localdomain' - 'vsys': - description: 'The vsys.' - default: 'vsys1' - validation: - not_values: - 'shared': 'The vsys cannot be "shared". Use the "shared" path instead.' - 'device_group': - description: 'Located in a specific device group.' - device: - panorama: true - xpath: - - 'config' - - 'devices' - - '{{ Entry $panorama_device }}' - - 'device-group' - - '{{ Entry $device_group }}' - vars: - 'panorama_device': - description: 'The panorama device.' - default: 'localhost.localdomain' - 'device_group': - description: 'The device group.' - required: true - validation: - not_values: - 'shared': 'The device group cannot be "shared". Use the "shared" path instead.' -entry: - name: - description: 'The name of the address object.' - length: - min: 1 - max: 63 -imports: - 'template': - xpath: - - 'config' - - 'devices' - - '{{ Entry $ngfw_device }}' - - 'vsys' - - '{{ Entry $vsys }}' - - 'import' - - 'network' - - 'interface' - vars: - 'ngfw_device': - description: 'The NGFW device.' - default: 'localhost.localdomain' - 'vsys': - description: 'The vsys.' - default: 'vsys1' - only_for_params: - - layer3 -version: '10.1.0' -spec: - params: - description: - description: 'The description.' - type: 'string' - length: - min: 0 - max: 1023 - profiles: - - - xpath: ["description"] - from_version: "10.1.1" - tags: - description: 'The administrative tags.' - type: 'list' - count: - max: 64 - items: - type: 'string' - length: - max: 127 - profiles: - - - type: 'member' - xpath: ["tag"] - one_of: - 'ip_netmask': - description: 'The IP netmask value.' - profiles: - - - xpath: ["ip-netmask"] - 'ip_range': - description: 'The IP range value.' - profiles: - - - xpath: ["ip-range"] - 'fqdn': - description: 'The FQDN value.' - regex: '^[a-zA-Z0-9_]([a-zA-Z0-9:_-])+[a-zA-Z0-9]$' - length: - min: 1 - max: 255 - profiles: - - - xpath: ["fqdn"] - 'ip_wildcard': - description: 'The IP wildcard value.' - profiles: - - - xpath: ["ip-wildcard"] - from_version: "11.1.2" -const: - color: - values: - red: - value: color1 - light green: - value: color9 - blue: - value: color3 -` +const addressSpecPath = "../../specs/objects/address.yaml" func TestUnmarshallAddressSpecFile(t *testing.T) { // given - + sampleSpec, err := os.ReadFile(addressSpecPath) + assert.Nil(t, err, "failed to read address spec") // when - yamlParsedData, _ := ParseSpec([]byte(sampleSpec)) + yamlParsedData, err := ParseSpec([]byte(sampleSpec)) + assert.Nil(t, err) // then assert.NotNilf(t, yamlParsedData, "Unmarshalled data cannot be nil") @@ -176,313 +30,6 @@ func TestUnmarshallAddressSpecFile(t *testing.T) { assert.NotNilf(t, yamlParsedData.Spec, "Unmarshalled data should contain `spec`") } -func TestMarshallAddressSpecFile(t *testing.T) { - // given - var expectedMarshalledData = `name: Address -terraform_provider_config: - skip_resource: false - skip_datasource: false - skip_datasource_listing: false - suffix: address -go_sdk_path: - - objects - - address -xpath_suffix: - - address -locations: - device_group: - name: - underscore: device_group - camelcase: DeviceGroup - lowercamelcase: deviceGroup - description: Located in a specific device group. - device: - panorama: true - ngfw: false - xpath: - - config - - devices - - '{{ Entry $panorama_device }}' - - device-group - - '{{ Entry $device_group }}' - read_only: false - vars: - device_group: - name: - underscore: device_group - camelcase: DeviceGroup - lowercamelcase: deviceGroup - description: The device group. - default: "" - required: true - validation: - not_values: - shared: The device group cannot be "shared". Use the "shared" path instead. - panorama_device: - name: - underscore: panorama_device - camelcase: PanoramaDevice - lowercamelcase: panoramaDevice - description: The panorama device. - default: localhost.localdomain - required: false - validation: null - from_panorama: - name: - underscore: from_panorama - camelcase: FromPanorama - lowercamelcase: fromPanorama - description: Located in the config pushed from Panorama. - device: - panorama: false - ngfw: true - xpath: - - config - - panorama - read_only: true - vars: {} - shared: - name: - underscore: shared - camelcase: Shared - lowercamelcase: shared - description: Located in shared. - device: - panorama: true - ngfw: true - xpath: - - config - - shared - read_only: false - vars: {} - vsys: - name: - underscore: vsys - camelcase: Vsys - lowercamelcase: vsys - description: Located in a specific vsys. - device: - panorama: true - ngfw: true - xpath: - - config - - devices - - '{{ Entry $ngfw_device }}' - - vsys - - '{{ Entry $vsys }}' - read_only: false - vars: - ngfw_device: - name: - underscore: ngfw_device - camelcase: NgfwDevice - lowercamelcase: ngfwDevice - description: The NGFW device. - default: localhost.localdomain - required: false - validation: null - vsys: - name: - underscore: vsys - camelcase: Vsys - lowercamelcase: vsys - description: The vsys. - default: vsys1 - required: false - validation: - not_values: - shared: The vsys cannot be "shared". Use the "shared" path instead. -entry: - name: - description: The name of the address object. - length: - min: 1 - max: 63 -imports: - template: - name: - underscore: template - camelcase: Template - lowercamelcase: template - xpath: - - config - - devices - - '{{ Entry $ngfw_device }}' - - vsys - - '{{ Entry $vsys }}' - - import - - network - - interface - vars: - ngfw_device: - name: - underscore: ngfw_device - camelcase: NgfwDevice - lowercamelcase: ngfwDevice - description: The NGFW device. - default: localhost.localdomain - vsys: - name: - underscore: vsys - camelcase: Vsys - lowercamelcase: vsys - description: The vsys. - default: vsys1 - only_for_params: - - layer3 -version: 10.1.0 -spec: - params: - description: - name: - underscore: description - camelcase: Description - lowercamelcase: description - description: The description. - type: string - default: "" - required: false - sensitive: false - length: - min: 0 - max: 1023 - profiles: - - xpath: - - description - not_present: false - from_version: 10.1.1 - spec: null - tags: - name: - underscore: tags - camelcase: Tags - lowercamelcase: tags - description: The administrative tags. - type: list - default: "" - required: false - sensitive: false - count: - min: null - max: 64 - items: - type: string - length: - min: null - max: 127 - ref: [] - profiles: - - xpath: - - tag - type: member - not_present: false - from_version: "" - spec: null - one_of: - fqdn: - name: - underscore: fqdn - camelcase: Fqdn - lowercamelcase: fqdn - description: The FQDN value. - type: string - default: "" - required: false - sensitive: false - length: - min: 1 - max: 255 - regex: ^[a-zA-Z0-9_]([a-zA-Z0-9:_-])+[a-zA-Z0-9]$ - profiles: - - xpath: - - fqdn - not_present: false - from_version: "" - spec: null - ip_netmask: - name: - underscore: ip_netmask - camelcase: IpNetmask - lowercamelcase: ipNetmask - description: The IP netmask value. - type: string - default: "" - required: false - sensitive: false - profiles: - - xpath: - - ip-netmask - not_present: false - from_version: "" - spec: null - ip_range: - name: - underscore: ip_range - camelcase: IpRange - lowercamelcase: ipRange - description: The IP range value. - type: string - default: "" - required: false - sensitive: false - profiles: - - xpath: - - ip-range - not_present: false - from_version: "" - spec: null - ip_wildcard: - name: - underscore: ip_wildcard - camelcase: IpWildcard - lowercamelcase: ipWildcard - description: The IP wildcard value. - type: string - default: "" - required: false - sensitive: false - profiles: - - xpath: - - ip-wildcard - not_present: false - from_version: 11.1.2 - spec: null -const: - color: - name: - underscore: color - camelcase: Color - lowercamelcase: color - values: - blue: - name: - underscore: blue - camelcase: Blue - lowercamelcase: blue - value: color3 - light green: - name: - underscore: light_green - camelcase: LightGreen - lowercamelcase: lightGreen - value: color9 - red: - name: - underscore: red - camelcase: Red - lowercamelcase: red - value: color1 -` - - // when - yamlParsedData, _ := ParseSpec([]byte(sampleSpec)) - yamlDump, _ := yaml.Marshal(&yamlParsedData) - - // then - assert.NotNilf(t, yamlDump, "Marshalled data cannot be nil") - assert.Equal(t, expectedMarshalledData, string(yamlDump), "Marshalled data differs from expected") -} - func TestGetNormalizations(t *testing.T) { // given @@ -541,27 +88,3 @@ xpath_suffix: // then assert.Len(t, problems, 2, "Not all expected validation checks failed") } - -func TestGettingListOfSupportedVersions(t *testing.T) { - // given - yamlParsedData, _ := ParseSpec([]byte(sampleSpec)) - - // when - versions := yamlParsedData.SupportedVersions() - - // then - assert.NotNilf(t, yamlParsedData, "Unmarshalled data cannot be nil") - assert.Contains(t, versions, "10.1.1") -} - -func TestCustomType(t *testing.T) { - // given - - // when - yamlParsedData, _ := ParseSpec([]byte(sampleSpec)) - - // then - assert.NotNil(t, yamlParsedData.Const) - assert.Equal(t, "Red", yamlParsedData.Const["color"].Values["red"].Name.CamelCase) - assert.Equal(t, "color1", yamlParsedData.Const["color"].Values["red"].Value) -} diff --git a/pkg/schema/imports/import.go b/pkg/schema/imports/import.go new file mode 100644 index 00000000..d188536e --- /dev/null +++ b/pkg/schema/imports/import.go @@ -0,0 +1,9 @@ +package imports + +import "github.com/paloaltonetworks/pan-os-codegen/pkg/schema/xpath" + +type Import struct { + Name string `yaml:"name"` + Xpath xpathschema.Xpath `yaml:"xpath"` + OnlyForParams []string `yaml:"only_for_params"` +} diff --git a/pkg/schema/location/location.go b/pkg/schema/location/location.go new file mode 100644 index 00000000..e060b397 --- /dev/null +++ b/pkg/schema/location/location.go @@ -0,0 +1,21 @@ +package location + +import ( + validatorschema "github.com/paloaltonetworks/pan-os-codegen/pkg/schema/validator" + xpathschema "github.com/paloaltonetworks/pan-os-codegen/pkg/schema/xpath" +) + +type Device string + +const ( + DevicePanorama Device = "panorama" + DeviceNgfw Device = "ngfw" +) + +type Location struct { + Name string `yaml:"name"` + Description string `yaml:"description"` + Devices []Device `yaml:"devices"` + Xpath xpathschema.Xpath `yaml:"xpath"` + Validators []*validatorschema.Validator `yaml:"validators"` +} diff --git a/pkg/schema/object/object.go b/pkg/schema/object/object.go new file mode 100644 index 00000000..2d87a676 --- /dev/null +++ b/pkg/schema/object/object.go @@ -0,0 +1,59 @@ +package object + +import ( + "gopkg.in/yaml.v3" + + "github.com/paloaltonetworks/pan-os-codegen/pkg/schema/imports" + "github.com/paloaltonetworks/pan-os-codegen/pkg/schema/location" + "github.com/paloaltonetworks/pan-os-codegen/pkg/schema/parameter" + "github.com/paloaltonetworks/pan-os-codegen/pkg/schema/validator" +) + +type TerraformConfig struct { + SkipResource bool `yaml:"skip_resource"` + SkipDatasource bool `yaml:"skip_datasource"` + SkipdatasourceListing bool `yaml:"skip_datasource_listing"` + Suffix string `yaml:"suffix"` +} + +type GoSdkConfig struct { + Package []string +} + +type Entry struct { + Name string `yaml:"name"` + Description string `yaml:"descripion"` + Validators []*validator.Validator `yaml:"validators"` +} + +type Spec struct { + Required bool `yaml:"required"` + Parameters []*parameter.Parameter `yaml:"params"` + Variants []*parameter.Parameter `yaml:"variants"` +} + +type Object struct { + Name string `yaml:"-"` + DisplayName string `yaml:"name"` + XpathSuffix []string `yaml:"xpath_suffix"` + TerraformConfig *TerraformConfig `yaml:"terraform_provider_config"` + Version string `yaml:"version"` + GoSdkConfig *GoSdkConfig `yaml:"go_sdk_config"` + Locations []location.Location `yaml:"locations"` + Entries []Entry `yaml:"entries"` + Imports []imports.Import `yaml:"imports"` + Spec *Spec `yaml:"spec"` +} + +func NewFromBytes(name string, objectBytes []byte) (*Object, error) { + var object Object + + err := yaml.Unmarshal(objectBytes, &object) + if err != nil { + return nil, err + } + + object.Name = name + + return &object, nil +} diff --git a/pkg/schema/object/object_suite_test.go b/pkg/schema/object/object_suite_test.go new file mode 100644 index 00000000..e4b6f34a --- /dev/null +++ b/pkg/schema/object/object_suite_test.go @@ -0,0 +1,15 @@ +package object_test + +import ( + "log/slog" + "testing" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" +) + +func TestObject(t *testing.T) { + slog.SetDefault(slog.New(slog.NewTextHandler(GinkgoWriter, &slog.HandlerOptions{Level: slog.LevelDebug}))) + RegisterFailHandler(Fail) + RunSpecs(t, "Object Suite") +} diff --git a/pkg/schema/parameter/parameter.go b/pkg/schema/parameter/parameter.go new file mode 100644 index 00000000..7b6106b6 --- /dev/null +++ b/pkg/schema/parameter/parameter.go @@ -0,0 +1,185 @@ +package parameter + +import ( + "fmt" + "log/slog" + + "gopkg.in/yaml.v3" + + "github.com/paloaltonetworks/pan-os-codegen/pkg/errors" + "github.com/paloaltonetworks/pan-os-codegen/pkg/schema/profile" + "github.com/paloaltonetworks/pan-os-codegen/pkg/schema/validator" +) + +// Parameter describes a single parameter for the given object spec. +// +// Parameter can describe both a top-level parameter of the object +// or nested parameter of another object parameter. +// +// Spec type is any, as its unmarshalling is done in a custom +// UnmarshalYAML function. +type Parameter struct { + Name string `yaml:"name"` + Description string `yaml:"description"` + Type string `yaml:"type"` + CodegenOverrides *CodegenOverrides `yaml:"codegen_overrides"` + Required bool `yaml:"required"` + Profiles []profile.Profile `yaml:"profiles"` + Validators []validator.Validator `yaml:"validators"` + Spec any `yaml:"-"` +} + +// SimpleSpec describes a parameter of a simple type. +type SimpleSpec struct { + Default any `yaml:"default"` + Required bool `yaml:"required"` +} + +// EnumSpecValue describes a single enum value. +type EnumSpecValue struct { + Value string `yaml:"value"` + Const string `yaml:"const"` +} + +type CodegenOverridesTerraform struct { + Computed bool `yaml:"computed"` +} + +type CodegenOverrides struct { + Terraform *CodegenOverridesTerraform `yaml:"terraform"` +} + +// EnumSpec describes a parameter of type enum +// +// Values is a list of EnumSpecValue, where each one consisting of the PAN-OS Value +// and its optional Const representation. This allows to generate a more meaningful +// types, for example when spec value is "color1", and its const is "red", the following +// type will be marshalled for pan-os-go SDK: +// +// ParameterRed ParameterType = "color1" +// +// when spec value is "up" and spec const is empty, the following type will be marshalled +// instead: +// +// ParameterUp ParameterType = "up" +type EnumSpec struct { + Required bool `yaml:"required"` + Default string `yaml:"default"` + Values []EnumSpecValue `yaml:"values"` +} + +type StructSpec struct { + Required bool `yaml:"required"` + Parameters []*Parameter `yaml:"params"` + Variants []*Parameter `yaml:"variants"` +} + +type ListSpecElement struct { + Type string `yaml:"type"` + Required bool `yaml:"required"` + Spec StructSpec `yaml:"spec"` +} + +type ListSpec struct { + Required bool `yaml:"required"` + Items ListSpecElement `yaml:"items"` +} + +type NilSpec struct{} + +// UnmarshalYAML implements custom unmarshalling logic for parameters +// +// When unmarshalling yaml objects into parameters, their spec is unmarshalled +// into different structures based on the spec type. This custom UnmarshalYAML +// functions handles this logic. +func (p *Parameter) UnmarshalYAML(n *yaml.Node) error { + // Create an empty Parameter value and a new temporary structure + // that is based on the parameter, but overrides Spec field to be + // of a generic yaml.Node type. + // This new type, and the casting below is needed so that yaml + // unmarshaller doesn't recursively call UnmarshalYAML. + type P Parameter + type S struct { + *P `yaml:",inline"` + Spec yaml.Node `yaml:"spec"` + } + + // Cast "this" parameter pointer to a new S type and then decode + // entire parameter yaml object into this new object. This will + // unmarshal spec field from yaml into yaml.Node Spec field in the + // temporary structure. + obj := &S{P: (*P)(p)} + if err := n.Decode(obj); err != nil { + return err + } + + // Now that we have unmarshalled entire parameter object into a temporary + // structure, we can assign proper structure to the parameter Spec field. + switch p.Type { + case "object": + p.Spec = new(StructSpec) + case "list": + p.Spec = new(ListSpec) + case "enum": + p.Spec = new(EnumSpec) + case "nil": + p.Spec = new(NilSpec) + case "string", "bool", "int64": + p.Spec = new(SimpleSpec) + default: + return errors.NewSchemaError(fmt.Sprintf("unsupported parameter type: '%s'", p.Type)) + } + + // Finally, decode obj.Spec (which is yaml.Node type) into the parameter + // spec structure + return obj.Spec.Decode(p.Spec) +} + +// SingularName returns a singular name for parameter. +// +// When Parameter type is list, and list profile type is either +// "entry" or "member", we us first path of an profile xpath array +// to determine a singular name for the given parameter. +// +// When called for non-list parameters, parameter name is returned +// instead. +func (p *Parameter) SingularName() string { + switch p.Spec.(type) { + case *ListSpec: + var singularName string + for _, profile := range p.Profiles { + switch profile.Type { + case "entry", "member": + if len(profile.Xpath) >= 1 { + singularName = profile.Xpath[0] + } + } + } + + if singularName == "" { + slog.Warn("Couldn't generate singular name for list parameter", "parameter", p.Name) + } + + return singularName + } + + return p.Name +} + +// SpecItemsType is a shorthand accessor to list items type +// +// When checking parameter list item type, parameter's spec has to +// be first cast to the ListSpec type. This function gives +// a quick access to the type without having to do casting manually. +// +// When called on any other parameter type, it returns an empty +// string, so the caller (mostly templates) must ensure that it's +// being called on list parameters. +func (p *Parameter) SpecItemsType() string { + switch spec := p.Spec.(type) { + case *ListSpec: + return spec.Items.Type + default: + return "" + } +} diff --git a/pkg/schema/parameter/parameter_suite_test.go b/pkg/schema/parameter/parameter_suite_test.go new file mode 100644 index 00000000..d3502190 --- /dev/null +++ b/pkg/schema/parameter/parameter_suite_test.go @@ -0,0 +1,13 @@ +package parameter_test + +import ( + "testing" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" +) + +func TestParameter(t *testing.T) { + RegisterFailHandler(Fail) + RunSpecs(t, "Parameter Suite") +} diff --git a/pkg/schema/parameter/parameter_test.go b/pkg/schema/parameter/parameter_test.go new file mode 100644 index 00000000..58bf6d51 --- /dev/null +++ b/pkg/schema/parameter/parameter_test.go @@ -0,0 +1,81 @@ +package parameter_test + +import ( + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + "gopkg.in/yaml.v3" + + "github.com/paloaltonetworks/pan-os-codegen/pkg/schema/parameter" + "github.com/paloaltonetworks/pan-os-codegen/pkg/schema/profile" +) + +var _ = Describe("Parameter", func() { + Describe("When unmarshalling YAML object into parameter", func() { + Context("with parameter type set to nil", func() { + It("should unmarshal into Parameter with ParameterNilSpec Spec", func() { + bytes := []byte(`{name: test-param, type: nil, profiles: [], spec: {}}`) + var param parameter.Parameter + err := yaml.Unmarshal(bytes, ¶m) + Expect(err).ToNot(HaveOccurred()) + }) + }) + }) + Describe("When a list parameter is created", func() { + Context("with required set to true, items' type set to a simple type and with singular profile xpath", func() { + var param parameter.Parameter + BeforeEach(func() { + param = parameter.Parameter{ + Name: "test-params", + Required: true, + Type: "list", + Spec: ¶meter.ListSpec{ + Items: parameter.ListSpecElement{ + Type: "string", + }, + }, + Profiles: []profile.Profile{ + { + Type: "entry", + Xpath: []string{"test-param"}, + }, + }, + } + }) + It("the required state should be correct", func() { + Expect(param.Required).To(BeTrue()) + }) + It("the SpecItemsType shortcut should return correct type of the items", func() { + Expect(param.SpecItemsType()).To(Equal("string")) + }) + It("the singular name should be properly generated", func() { + Expect(param.SingularName()).To(Equal("test-param")) + }) + }) + Context("with required not set explicitly", func() { + var param parameter.Parameter + BeforeEach(func() { + param = parameter.Parameter{ + Name: "test-params", + Type: "list", + Spec: ¶meter.ListSpec{ + Items: parameter.ListSpecElement{ + Type: "object", + }, + }, + Profiles: []profile.Profile{ + { + Type: "entry", + Xpath: []string{"test-param", "entry"}, + }, + }, + } + }) + It("the required should return false", func() { + Expect(param.Required).To(BeFalse()) + }) + It("the singular name should be properly generated", func() { + Expect(param.SingularName()).To(Equal("test-param")) + }) + }) + }) +}) diff --git a/pkg/schema/profile/profile.go b/pkg/schema/profile/profile.go new file mode 100644 index 00000000..a9419d59 --- /dev/null +++ b/pkg/schema/profile/profile.go @@ -0,0 +1,16 @@ +package profile + +import "github.com/paloaltonetworks/pan-os-codegen/pkg/version" + +// Profile describes parameter versioning information +// +// MinimumVersion and MaximumVersion can be used to limit +// parameter visibility across PAN-OS versions. This is used +// in the marshalling/unmarshalling code to generate per-version +// structures and properly marshal objects into XML documents. +type Profile struct { + Type string `yaml:"type"` + MinimumVersion *version.Version `yaml:"min_version"` + MaximumVersion *version.Version `yaml:"max_version"` + Xpath []string `yaml:"xpath"` +} diff --git a/pkg/schema/validator/validators.go b/pkg/schema/validator/validators.go new file mode 100644 index 00000000..f4ad968e --- /dev/null +++ b/pkg/schema/validator/validators.go @@ -0,0 +1,101 @@ +package validator + +import ( + "fmt" + + "gopkg.in/yaml.v3" + + "github.com/paloaltonetworks/pan-os-codegen/pkg/errors" +) + +// Validator describes any validator that can be defined across +// xpath variables, locations, entries and parameters. +// +// Spec type is any, as its unmarshalling is done in a custom +// UnmarshalYAML function. +type Validator struct { + Type string `yaml:"type"` + Spec any `yaml:"-"` +} + +// UnmarshalYAML implements custom unmarshalling logic for parameters +// +// When unmarshalling yaml objects into parameters, their spec is unmarshalled +// into different structures based on the spec type. This custom UnmarshalYAML +// +// For a detailed description of how this is achieved check `parameter.Parameter` +// documentation. +func (v *Validator) UnmarshalYAML(n *yaml.Node) error { + type V Validator + type S struct { + *V `yaml:",inline"` + Spec yaml.Node `yaml:"spec"` + } + + obj := &S{V: (*V)(v)} + if err := n.Decode(obj); err != nil { + return err + } + + switch v.Type { + case "length": + v.Spec = new(StringLengthSpec) + case "values": + v.Spec = new(ValuesSpec) + case "not-values": + v.Spec = new(NotValuesSpec) + case "range": + v.Spec = new(RangeSpec) + case "count": + v.Spec = new(CountSpec) + case "regexp": + v.Spec = new(RegexpSpec) + case "required": + v.Spec = new(RequiredSpec) + default: + return errors.NewSchemaError(fmt.Sprintf("unsupported validator: '%s'", obj.Type)) + } + + return obj.Spec.Decode(v.Spec) +} + +// RequiredSpec validates that a given value is set. +type RequiredSpec struct{} + +// StringLengthSpec validates given string's length. +type StringLengthSpec struct { + Min int + Max int +} + +// ValuesSpec validates that a given value is within validator values. +type ValuesSpec struct { + Values []any +} + +type NotValuesSpecItem struct { + Value string + Error string +} + +// NotValuesSpec validates that a given value is not withing validator values. +type NotValuesSpec struct { + Values []NotValuesSpecItem +} + +// RangeSpec validates that a given numeric value is within a given range. +type RangeSpec struct { + Min int + Max int +} + +// CountSpec validates that a given slice length is within a given range. +type CountSpec struct { + Min int + Max int +} + +// RegexpSpec validates that a given value matches regex expression. +type RegexpSpec struct { + Expr string +} diff --git a/pkg/schema/xpath/xpath.go b/pkg/schema/xpath/xpath.go new file mode 100644 index 00000000..d70ed674 --- /dev/null +++ b/pkg/schema/xpath/xpath.go @@ -0,0 +1,57 @@ +package xpathschema + +import ( + "gopkg.in/yaml.v3" + + "github.com/paloaltonetworks/pan-os-codegen/pkg/schema/validator" +) + +type VariableType string + +const ( + VariableEntry VariableType = "entry" + VariableObject VariableType = "object" +) + +// Variable describes a single xpath variable +// +// Xpath variables are used to dynamically render parts of the +// object xpath, using custom logic from pan-os-go utils. +type Variable struct { + Name string `yaml:"name"` + Description string `yaml:"description"` + Required bool `yaml:"required"` + Type VariableType `yaml:"type"` + Default string `yaml:"default"` + Validators []validator.Validator `yaml:"validators"` +} + +// Xpath describes xpath as used by locations and imports +// +// Xpath Elements that start with '$' character are variables, +// defined in the Variables field. +type Xpath struct { + Elements []string `yaml:"path"` + Variables []Variable `yaml:"vars"` +} + +// UnmarshalYAML implements unmarshalling with default Type. +// +// This is temporary logic that sets default Type for all variables +// that have no type set explicitly. It can be removed once all +// schemas are generated from the XML source. +func (o *Variable) UnmarshalYAML(n *yaml.Node) error { + type V Variable + + obj := (*V)(o) + err := n.Decode(obj) + if err != nil { + return err + } + + if o.Type == "" { + o.Type = "entry" + } + + return nil +} diff --git a/pkg/schema/xpath/xpath_suite_test.go b/pkg/schema/xpath/xpath_suite_test.go new file mode 100644 index 00000000..5073a090 --- /dev/null +++ b/pkg/schema/xpath/xpath_suite_test.go @@ -0,0 +1,19 @@ +package xpathschema_test + +import ( + "log/slog" + "testing" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" +) + +func TestXpath(t *testing.T) { + handler := slog.NewTextHandler( + GinkgoWriter, + &slog.HandlerOptions{Level: slog.LevelDebug}, + ) + slog.SetDefault(slog.New(handler)) + RegisterFailHandler(Fail) + RunSpecs(t, "Xpath Suite") +} diff --git a/pkg/schema/xpath/xpath_test.go b/pkg/schema/xpath/xpath_test.go new file mode 100644 index 00000000..cbbace8d --- /dev/null +++ b/pkg/schema/xpath/xpath_test.go @@ -0,0 +1,34 @@ +package xpathschema_test + +import ( + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + "gopkg.in/yaml.v3" + + "github.com/paloaltonetworks/pan-os-codegen/pkg/schema/xpath" +) + +var _ = Describe("Variable", func() { + Describe("When unmarshalling yaml document", func() { + Context("with type set to non-empty string", func() { + It("should create a valid Variable", func() { + data := []byte(`{name: variable, type: object}`) + var variable xpathschema.Variable + err := yaml.Unmarshal(data, &variable) + Expect(err).ToNot(HaveOccurred()) + Expect(variable.Name).To(Equal("variable")) + Expect(variable.Type).To(Equal(xpathschema.VariableObject)) + }) + }) + Context("with type left unset", func() { + It("should create a valid Variable with type entry", func() { + data := []byte(`{name: variable}`) + var variable xpathschema.Variable + err := yaml.Unmarshal(data, &variable) + Expect(err).ToNot(HaveOccurred()) + Expect(variable.Name).To(Equal("variable")) + Expect(variable.Type).To(Equal(xpathschema.VariableEntry)) + }) + }) + }) +}) diff --git a/pkg/translate/structs.go b/pkg/translate/structs.go index ec7f7718..f289b152 100644 --- a/pkg/translate/structs.go +++ b/pkg/translate/structs.go @@ -182,7 +182,7 @@ func ParamSupportedInVersion(param *properties.SpecParam, deviceVersionStr strin if deviceVersionStr == "" { supported = listOfProfileSupportForNotDefinedDeviceVersion(param, supported) } else { - deviceVersion, err := version.New(deviceVersionStr) + deviceVersion, err := version.NewVersionFromString(deviceVersionStr) if err != nil { return false } @@ -209,12 +209,12 @@ func listOfProfileSupportForNotDefinedDeviceVersion(param *properties.SpecParam, func listOfProfileSupportForDefinedDeviceVersion(param *properties.SpecParam, supported []bool, deviceVersion version.Version) ([]bool, error) { for _, profile := range param.Profiles { if profile.FromVersion != "" { - paramProfileVersion, err := version.New(profile.FromVersion) + paramProfileVersion, err := version.NewVersionFromString(profile.FromVersion) if err != nil { return nil, err } - if deviceVersion.Gte(paramProfileVersion) { + if deviceVersion.GreaterThanOrEqualTo(paramProfileVersion) { supported = append(supported, !profile.NotPresent) } else { supported = append(supported, profile.NotPresent) diff --git a/pkg/translate/structs_test.go b/pkg/translate/structs_test.go index 44b57982..13d27f8e 100644 --- a/pkg/translate/structs_test.go +++ b/pkg/translate/structs_test.go @@ -1,6 +1,7 @@ package translate import ( + "os" "testing" "github.com/stretchr/testify/assert" @@ -8,56 +9,14 @@ import ( "github.com/paloaltonetworks/pan-os-codegen/pkg/properties" ) -const sampleSpec = `name: 'Address' -terraform_provider_config: - skip_resource: false - skip_datasource: false - skip_datasource_listing: false - suffix: address -go_sdk_path: - - 'objects' - - 'address' -xpath_suffix: - - 'address' -locations: - 'shared': - description: 'Located in shared.' - device: - panorama: true - ngfw: true - xpath: ['config', 'shared'] - 'device_group': - description: 'Located in a specific device group.' - device: - panorama: true - xpath: - - 'config' - - 'devices' - - '{{ Entry $panorama_device }}' - - 'device-group' - - '{{ Entry $device_group }}' - vars: - 'panorama_device': - description: 'The panorama device.' - default: 'localhost.localdomain' - 'device_group': - description: 'The device group.' - required: true - validation: - not_values: - 'shared': 'The device group cannot be "shared". Use the "shared" path instead.' -entry: - name: - description: 'The name of the address object.' - length: - min: 1 - max: 63 -version: '10.1.0' -` +const addressSpecPath = "../../specs/objects/address.yaml" func TestLocationType(t *testing.T) { + sampleSpec, err := os.ReadFile(addressSpecPath) + assert.Nil(t, err, "failed to read address spec") // given yamlParsedData, _ := properties.ParseSpec([]byte(sampleSpec)) + locationKeys := []string{"device_group", "shared"} locations := yamlParsedData.Locations var locationTypes []string @@ -102,6 +61,9 @@ func TestSpecParamType(t *testing.T) { } func TestOmitEmpty(t *testing.T) { + sampleSpec, err := os.ReadFile(addressSpecPath) + assert.Nil(t, err, "failed to read address spec") + // given yamlParsedData, _ := properties.ParseSpec([]byte(sampleSpec)) locationKeys := []string{"device_group", "shared"} diff --git a/pkg/version/version.go b/pkg/version/version.go index 7bcf8f4c..322e1874 100644 --- a/pkg/version/version.go +++ b/pkg/version/version.go @@ -1,72 +1,144 @@ package version import ( - "errors" "fmt" "strconv" "strings" + + "gopkg.in/yaml.v3" ) -// Version is the version number struct. +// Version represents PAN-OS version split into its components type Version struct { Major, Minor, Patch int Hotfix string } -// Gte tests if this version number is greater than or equal to the argument. -func (v Version) Gte(o Version) bool { - if v.Major != o.Major { - return v.Major > o.Major +// NewVersionFromString creates a new Version value from a given string +func NewVersionFromString(version string) (Version, error) { + parts := strings.Split(version, ".") + if len(parts) != 3 { + return Version{}, fmt.Errorf("invalid version string: not enough components") } - if v.Minor != o.Minor { - return v.Minor > o.Minor + major, err := strconv.Atoi(parts[0]) + if err != nil { + return Version{}, fmt.Errorf("invalid version string: major component must be a number") } - return v.Patch >= o.Patch -} + minor, err := strconv.Atoi(parts[1]) + if err != nil { + return Version{}, fmt.Errorf("invalid version string: minor component must be a number") + } -// String returns the version number as a string. -func (v Version) String() string { - if v.Hotfix == "" { - return fmt.Sprintf("%d.%d.%d", v.Major, v.Minor, v.Patch) + patchParts := strings.Split(parts[2], "-") + + var patch int + var hotfix string + if len(patchParts) == 1 { + patch, err = strconv.Atoi(parts[2]) + if err != nil { + return Version{}, fmt.Errorf("invalid version string: patch component must be a number") + } } else { - return fmt.Sprintf("%d.%d.%d-%s", v.Major, v.Minor, v.Patch, v.Hotfix) + if patchParts[1] == "" { + return Version{}, fmt.Errorf("invalid version string: hotfix part must be set") + } + patch, err = strconv.Atoi(patchParts[0]) + if err != nil { + return Version{}, fmt.Errorf("invalid version string: patch component must be a number") + } + hotfix = patchParts[1] } + + return Version{ + Major: major, + Minor: minor, + Patch: patch, + Hotfix: hotfix, + }, nil + } -// New returns a version number from the given string. -func New(version string) (Version, error) { - parts := strings.Split(version, ".") - if len(parts) != 3 { - return Version{}, errors.New("invalid version") +// UnmarshalYAML implements custom unmarshalling of YAML data into Version +func (v *Version) UnmarshalYAML(node *yaml.Node) error { + var versionString string + if err := node.Decode(&versionString); err != nil { + return fmt.Errorf("failed to unmarshal YAML structure: %w", err) } - major, err := strconv.Atoi(parts[0]) + decoded, err := NewVersionFromString(versionString) if err != nil { - return Version{}, fmt.Errorf("major %s is not a number: %w", parts[0], err) + return err } - minor, err := strconv.Atoi(parts[1]) - if err != nil { - return Version{}, fmt.Errorf("minor %s is not a number: %w", parts[0], err) + *v = decoded + + return nil +} + +// String() returns a string representation of the Version value +func (v Version) String() string { + version := fmt.Sprintf("%d.%d.%d", v.Major, v.Minor, v.Patch) + if v.Hotfix != "" { + version = fmt.Sprintf("%s-%s", version, v.Hotfix) } - patchWithHotfix := strings.Split(parts[2], "-") + return version +} - var hotfix string - if len(patchWithHotfix) == 1 { - hotfix = "" - } else if len(patchWithHotfix) == 2 { - hotfix = patchWithHotfix[1] - } else { - return Version{}, fmt.Errorf("patch %s is not formatted as expected", parts[2]) +// LesserThan implements lesser than +// +// This function, just like other boolean comparisons ignore any value +// of the Hotfix field. +func (v Version) LesserThan(o Version) bool { + if v.Major != o.Major { + return v.Major < o.Major } - patch, err := strconv.Atoi(patchWithHotfix[0]) - if err != nil { - return Version{}, fmt.Errorf("patch %s is not a number: %w", parts[2], err) + if v.Minor != o.Minor { + return v.Minor < o.Minor + } + + return v.Patch < o.Patch +} + +// EqualTo implements equality comparison +// +// This function, just like other boolean comparisons ignore any value +// of the Hotfix field. +func (v Version) EqualTo(o Version) bool { + return v.Major == o.Major && v.Minor == o.Minor && v.Patch == o.Patch +} + +// GreaterThan implements greater than comparison +// +// This function, just like other boolean comparisons ignore any value +// of the Hotfix field. +func (v Version) GreaterThan(o Version) bool { + if v.Major != o.Major { + return v.Major > o.Major + } + + if v.Minor != o.Minor { + return v.Minor > o.Minor } - return Version{major, minor, patch, hotfix}, nil + return v.Patch > o.Patch +} + +// GreatherThanOrEqualTo implements greater or equal comparison +// +// This function, just like other boolean comparisons ignore any value +// of the Hotfix field. +func (v Version) GreaterThanOrEqualTo(o Version) bool { + return v.EqualTo(o) || v.GreaterThan(o) +} + +// LesserThanOrEqualTo implemets lesser or equal comparison +// +// This function, just like other boolean comparisons ignore any value +// of the Hotfix field. +func (v Version) LesserThanOrEqualTo(o Version) bool { + return v.EqualTo(o) || v.LesserThan(o) } diff --git a/pkg/version/version_suite_test.go b/pkg/version/version_suite_test.go new file mode 100644 index 00000000..a115d9d8 --- /dev/null +++ b/pkg/version/version_suite_test.go @@ -0,0 +1,15 @@ +package version_test + +import ( + "log/slog" + "testing" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" +) + +func TestVersion(t *testing.T) { + slog.SetDefault(slog.New(slog.NewTextHandler(GinkgoWriter, &slog.HandlerOptions{Level: slog.LevelDebug}))) + RegisterFailHandler(Fail) + RunSpecs(t, "Version Suite") +} diff --git a/pkg/version/version_test.go b/pkg/version/version_test.go index 54bd2665..12a7b772 100644 --- a/pkg/version/version_test.go +++ b/pkg/version/version_test.go @@ -1,50 +1,143 @@ -package version +package version_test import ( - "testing" + "fmt" - "github.com/stretchr/testify/assert" -) - -func TestCorrectVersion(t *testing.T) { - // given - - // when - version1011, err1011 := New("10.1.1") - version1011h2, err1011h2 := New("10.1.1-h2") - - // then - assert.NoError(t, err1011) - assert.Equal(t, 10, version1011.Major) - assert.Equal(t, 1, version1011.Minor) - assert.Equal(t, 1, version1011.Patch) - assert.Equal(t, "", version1011.Hotfix) - assert.NoError(t, err1011h2) - assert.Equal(t, 10, version1011h2.Major) - assert.Equal(t, 1, version1011h2.Minor) - assert.Equal(t, 1, version1011h2.Patch) - assert.Equal(t, "h2", version1011h2.Hotfix) -} + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + "gopkg.in/yaml.v3" -func TestIncorrectVersion(t *testing.T) { - // given - - // when - _, err101 := New("10.1") - _, err1011h2h2 := New("10.1.1-h2-h2") - - // then - assert.Error(t, err101) - assert.Error(t, err1011h2h2) -} - -func TestVersionComparison(t *testing.T) { - // given + "github.com/paloaltonetworks/pan-os-codegen/pkg/version" +) - // when - v1, _ := New("10.1.1") - v2, _ := New("10.2.1-h2") +var _ = Describe("Version", func() { + Context("when version is unmarshalled from yaml", func() { + Context("with invalid yaml data", func() { + It("should return a wrapped error", func() { + data := "-" + var v version.Version + err := yaml.Unmarshal([]byte(data), &v) + Expect(err).Should(MatchError(MatchRegexp("failed to unmarshal YAML structure:.+"))) + }) + }) + Context("with an invalid string version", func() { + var v version.Version + Context("where not all components are set", func() { - // then - assert.True(t, v2.Gte(v1)) -} + It("should return an error", func() { + data := "10" + err := yaml.Unmarshal([]byte(data), &v) + Expect(err).Should(MatchError(fmt.Errorf("invalid version string: not enough components"))) + }) + }) + Context("where major component is not a number", func() { + It("should return an error", func() { + data := "a.b.c" + err := yaml.Unmarshal([]byte(data), &v) + Expect(err).Should(MatchError(MatchRegexp(".*major component must be a number$"))) + }) + }) + Context("where minor component is not a number", func() { + It("should return an error", func() { + data := "10.b.c" + err := yaml.Unmarshal([]byte(data), &v) + Expect(err).Should(MatchError(MatchRegexp(".*minor component must be a number$"))) + }) + }) + Context("where patch component is not a number", func() { + It("should return an error", func() { + data := "10.0.c" + err := yaml.Unmarshal([]byte(data), &v) + Expect(err).Should(MatchError(MatchRegexp(".*patch component must be a number$"))) + }) + }) + Context("where hotfix component is empty", func() { + It("should return an error", func() { + data := "10.0.0-" + err := yaml.Unmarshal([]byte(data), &v) + Expect(err).Should(MatchError(MatchRegexp(".*hotfix part must be set"))) + }) + }) + Context("where patch component is not a number, and there is hotfix component", func() { + It("should return an error", func() { + data := "10.0.a-hotfix1" + err := yaml.Unmarshal([]byte(data), &v) + Expect(err).Should(MatchError(MatchRegexp(".*patch component must be a number"))) + }) + }) + }) + Context("with a hotfix", func() { + It("should have a proper struct representation", func() { + data := "10.0.0-hotfix1" + var v version.Version + err := yaml.Unmarshal([]byte(data), &v) + Expect(err).ShouldNot(HaveOccurred()) + Expect(v).To(Equal(version.Version{Major: 10, Minor: 0, Patch: 0, Hotfix: "hotfix1"})) + }) + }) + Context("without a hotfix", func() { + It("should have a proper struct representation", func() { + data := "10.0.0" + var v version.Version + err := yaml.Unmarshal([]byte(data), &v) + Expect(err).ShouldNot(HaveOccurred()) + Expect(v).To(Equal(version.Version{Major: 10, Minor: 0, Patch: 0})) + }) + }) + }) + Context("when version is rendered to a string", func() { + Context("with a hotfix", func() { + It("should render to a valid string representation", func() { + expected := "10.0.0-hotfix1" + v := version.Version{Major: 10, Minor: 0, Patch: 0, Hotfix: "hotfix1"} + Expect(v.String()).To(Equal(expected)) + }) + }) + Context("wthout a hotfix", func() { + It("should render to a valid string representation", func() { + expected := "10.0.0" + v := version.Version{Major: 10, Minor: 0, Patch: 0} + Expect(v.String()).To(Equal(expected)) + }) + }) + }) + Context("When comparing version against another", func() { + this := version.Version{Major: 10, Minor: 0, Patch: 0} + Context("where both versions are missing hotfix", func() { + other := version.Version{Major: 10, Minor: 0, Patch: 0} + It("version should be EqualTo other version", func() { + Expect(this.EqualTo(other)).To(BeTrue()) + }) + It("version should be GreaterThanOrEqualTo other version", func() { + Expect(this.GreaterThanOrEqualTo(other)).To(BeTrue()) + }) + It("version should be LesserThanOrEqualTo other version", func() { + Expect(this.LesserThanOrEqualTo(other)).To(BeTrue()) + }) + It("version should not be GreaterThan other version", func() { + Expect(this.GreaterThan(other)).To(BeFalse()) + }) + It("version should not be LesserThan other version", func() { + Expect(this.LesserThan(other)).To(BeFalse()) + }) + }) + Context("where one of versions has a hotfix", func() { + other := version.Version{Major: 10, Minor: 0, Patch: 0, Hotfix: "hotfix1"} + It("version should be EqualTo other version", func() { + Expect(this.EqualTo(other)).To(BeTrue()) + }) + It("version should be GreaterThanOrEqualTo other version", func() { + Expect(this.GreaterThanOrEqualTo(other)).To(BeTrue()) + }) + It("version should be LesserThanOrEqualTo other version", func() { + Expect(this.LesserThanOrEqualTo(other)).To(BeTrue()) + }) + It("version should not be GreaterThan other version", func() { + Expect(this.GreaterThan(other)).To(BeFalse()) + }) + It("version should not be LesserThan other version", func() { + Expect(this.LesserThan(other)).To(BeFalse()) + }) + }) + }) +}) diff --git a/specs/device/dns.yaml b/specs/device/dns.yaml index 6a2b0dad..a1b44161 100644 --- a/specs/device/dns.yaml +++ b/specs/device/dns.yaml @@ -1,108 +1,116 @@ -name: 'DNS' +name: "DNS" terraform_provider_config: - suffix: 'dns' -go_sdk_path: - - 'device' - - 'services' - - 'dns' + suffix: "dns" +go_sdk_config: + package: + - "device" + - "services" + - "dns" locations: - 'system': - description: 'Located in a system settings.' - device: - panorama: true - ngfw: true + - name: "system" + description: "Located in a system settings." + devices: + - panorama + - ngfw xpath: - - 'config' - - 'devices' - - '{{ Entry $ngfw_device }}' - - 'deviceconfig' - - 'system' - vars: - 'ngfw_device': - description: 'The NGFW device.' - default: 'localhost.localdomain' - 'template': - description: 'Located in a specific template.' - device: - panorama: true + path: + - "config" + - "devices" + - "$ngfw_device" + - "deviceconfig" + - "system" + vars: + - name: "ngfw_device" + description: "The NGFW device." + default: "localhost.localdomain" + - name: "template" + description: "Located in a specific template." + devices: + - panorama xpath: - - 'config' - - 'devices' - - '{{ Entry $panorama_device }}' - - 'template' - - '{{ Entry $template }}' - - 'config' - - 'devices' - - '{{ Entry $ngfw_device }}' - - 'deviceconfig' - - 'system' - vars: - 'panorama_device': - description: 'The panorama device.' - default: 'localhost.localdomain' - 'template': - description: 'The template.' - required: true - 'ngfw_device': - description: 'The NGFW device.' - default: 'localhost.localdomain' - 'template-stack': - description: 'Located in a specific template stack.' - device: - panorama: true + path: + - "config" + - "devices" + - "$panorama_device" + - "template" + - "$template" + - "config" + - "devices" + - "$ngfw_device" + - "deviceconfig" + - "system" + vars: + - name: "panorama_device" + description: "The panorama device." + default: "localhost.localdomain" + - name: "template" + description: "The template." + required: true + - name: "ngfw_device" + description: "The NGFW device." + default: "localhost.localdomain" + - name: "template-stack" + description: "Located in a specific template stack." + devices: + - panorama xpath: - - 'config' - - 'devices' - - '{{ Entry $panorama_device }}' - - 'template-stack' - - '{{ Entry $template_stack }}' - - 'config' - - 'devices' - - '{{ Entry $ngfw_device }}' - - 'deviceconfig' - - 'system' - vars: - 'panorama_device': - description: 'The panorama device.' - default: 'localhost.localdomain' - 'template_stack': - description: 'The template stack.' - required: true - 'ngfw_device': - description: 'The NGFW device.' - default: 'localhost.localdomain' -version: '10.1.0' + path: + - "config" + - "devices" + - "$panorama_device" + - "template-stack" + - "$template_stack" + - "config" + - "devices" + - "$ngfw_device" + - "deviceconfig" + - "system" + vars: + - name: "panorama_device" + description: "The panorama device." + default: "localhost.localdomain" + - name: "template_stack" + description: "The template stack." + required: true + - name: "ngfw_device" + description: "The NGFW device." + default: "localhost.localdomain" +version: "10.1.0" spec: params: - fqdn_refresh_time: - description: 'Seconds for Periodic Timer to refresh expired FQDN object entries' + - name: fqdn_refresh_time + description: "Seconds for Periodic Timer to refresh expired FQDN object entries" type: int64 - value: - min: 600 - max: 14399 + spec: default: 1800 + validators: + - type: range + spec: + min: 600 + max: 14399 profiles: - - - xpath: ["fqdn-refresh-time"] - dns_setting: - description: 'DNS settings' + - xpath: ["fqdn-refresh-time"] + - name: dns_setting + description: "DNS settings" + type: object profiles: - - - xpath: ["dns-setting"] + - xpath: ["dns-setting"] spec: params: - servers: - description: 'DNS servers' + - name: servers + description: "DNS servers" + type: object profiles: - - - xpath: ["servers"] + - xpath: ["servers"] spec: params: - primary: - description: 'Primary DNS server IP address' + - name: primary + description: "Primary DNS server IP address" + type: string profiles: - - xpath: [ "primary" ] - secondary: - description: 'Secondary DNS server IP address' + - xpath: ["primary"] + - name: secondary + description: "Secondary DNS server IP address" + type: string profiles: - - xpath: [ "secondary" ] + - xpath: ["secondary"] diff --git a/specs/device/ntp.yaml b/specs/device/ntp.yaml index 2fa22801..eed3feb9 100644 --- a/specs/device/ntp.yaml +++ b/specs/device/ntp.yaml @@ -1,214 +1,255 @@ name: "NTP" terraform_provider_config: suffix: "ntp" -go_sdk_path: - - "device" - - "services" - - "ntp" +go_sdk_config: + package: + - "device" + - "services" + - "ntp" locations: - "system": + - name: "system" description: "Located in a system settings." - device: - panorama: true - ngfw: true + devices: + - panorama + - ngfw xpath: - - "config" - - "devices" - - "{{ Entry $ngfw_device }}" - - "deviceconfig" - - "system" - vars: - "ngfw_device": - description: "The NGFW device." - default: "localhost.localdomain" - "template": + path: + - "config" + - "devices" + - "$ngfw_device" + - "deviceconfig" + - "system" + vars: + - name: "ngfw_device" + description: "The NGFW device." + default: "localhost.localdomain" + - name: "template" description: "Located in a specific template." - device: - panorama: true + devices: + - panorama xpath: - - "config" - - "devices" - - "{{ Entry $panorama_device }}" - - "template" - - "{{ Entry $template }}" - - "config" - - "devices" - - "{{ Entry $ngfw_device }}" - - "deviceconfig" - - "system" - vars: - "panorama_device": - description: "The panorama device." - default: "localhost.localdomain" - "template": - description: "The template." - required: true - "ngfw_device": - description: "The NGFW device." - default: "localhost.localdomain" - "template-stack": + path: + - "config" + - "devices" + - "$panorama_device" + - "template" + - "$template" + - "config" + - "devices" + - "$ngfw_device" + - "deviceconfig" + - "system" + vars: + - name: "panorama_device" + description: "The panorama device." + default: "localhost.localdomain" + - name: "template" + description: "The template." + required: true + - name: "ngfw_device" + description: "The NGFW device." + default: "localhost.localdomain" + - name: "template-stack" description: "Located in a specific template stack." - device: - panorama: true + devices: + - panorama xpath: - - "config" - - "devices" - - "{{ Entry $panorama_device }}" - - "template-stack" - - "{{ Entry $template_stack }}" - - "config" - - "devices" - - "{{ Entry $ngfw_device }}" - - "deviceconfig" - - "system" - vars: - "panorama_device": - description: "The panorama device." - default: "localhost.localdomain" - "template_stack": - description: "The template stack." - required: true - "ngfw_device": - description: "The NGFW device." - default: "localhost.localdomain" + path: + - "config" + - "devices" + - "$panorama_device" + - "template-stack" + - "$template_stack" + - "config" + - "devices" + - "$ngfw_device" + - "deviceconfig" + - "system" + vars: + - name: "panorama_device" + description: "The panorama device." + default: "localhost.localdomain" + - name: "template_stack" + description: "The template stack." + required: true + - name: "ngfw_device" + description: "The NGFW device." + default: "localhost.localdomain" version: "10.1.0" spec: params: - ntp_servers: + - name: ntp_servers + type: object description: "NTP servers" profiles: - xpath: ["ntp-servers"] spec: params: - primary_ntp_server: + - name: primary_ntp_server + type: object description: "Primary NTP Server Information" profiles: - xpath: ["primary-ntp-server"] spec: params: - ntp_server_address: + - name: ntp_server_address + type: string description: "NTP Server IP Address or Domain Name" profiles: - xpath: ["ntp-server-address"] - authentication_type: + - name: authentication_type + type: object description: "NTP Authentication" profiles: - xpath: ["authentication-type"] spec: - one_of: - none: + variants: + - name: none + type: nil description: "No NTP Authentication" profiles: - xpath: ["none"] - symmetric_key: + - name: symmetric_key + type: object description: "Symmetric Key Authentication" profiles: - xpath: ["symmetric-key"] spec: params: - key_id: + - name: key_id description: "Symmetric Key Number" type: int64 - value: - min: 1 - max: 65534 + validators: + - type: range + spec: + min: 1 + max: 65534 profiles: - xpath: ["key-id"] - one_of: - md5: + variants: + - name: md5 + type: string profiles: - xpath: ["algorithm", "md5"] spec: params: - authentication_key: + - name: authentication_key + type: string description: "Symmetric Key MD5 String" - sensitive: true + codegen_overrides: + terraform: + sensitive: true hashing: type: solo - length: - min: 6 - max: 32 + validators: + - type: length + spec: + min: 6 + max: 32 profiles: - xpath: ["authentication-key"] - sha1: + - name: sha1 + type: string profiles: - xpath: ["algorithm", "sha1"] spec: params: - authentication_key: + - name: authentication_key + type: string description: "Symmetric Key SHA1 Hexadecimal" - sensitive: true - length: - min: 40 - max: 40 + codegen_overrides: + terraform: + sensitive: true hashing: type: solo + validators: + - type: length + spec: + min: 40 + max: 40 profiles: - xpath: ["authentication-key"] - autokey: + - name: autokey + type: string description: "Autokey Authentication" profiles: - xpath: ["autokey"] - secondary_ntp_server: + - name: secondary_ntp_server + type: object description: "Secondary NTP Server Information" profiles: - xpath: ["secondary-ntp-server"] spec: params: - ntp_server_address: + - name: ntp_server_address + type: string description: "NTP Server IP Address or Domain Name" profiles: - xpath: ["ntp-server-address"] - authentication_type: + - name: authentication_type + type: object description: "NTP Authentication" profiles: - xpath: ["authentication-type"] spec: - one_of: - none: + variants: + - name: none + type: nil description: "No NTP Authentication" profiles: - xpath: ["none"] - symmetric_key: + - name: symmetric_key + type: object description: "Symmetric Key Authentication" profiles: - xpath: ["symmetric-key"] spec: params: - key_id: + - name: key_id description: "Symmetric Key Number" type: int64 - value: - min: 1 - max: 65534 + validators: + - type: range + spec: + min: 1 + max: 65534 profiles: - xpath: ["key-id"] - one_of: - md5: + variants: + - name: md5 + type: string profiles: - xpath: ["algorithm/md5"] spec: params: - authentication_key: + - name: authentication_key + type: string description: "Symmetric Key MD5 String" - length: - min: 6 - max: 32 + validators: + - type: length + spec: + min: 6 + max: 32 profiles: - xpath: ["authentication-key"] - sha1: + - name: sha1 + type: string profiles: - xpath: ["algorithm/sha1"] spec: params: - authentication_key: + - name: authentication_key + type: string description: "Symmetric Key SHA1 Hexadecimal" - length: - min: 40 - max: 40 + validators: + - type: length + spec: + min: 40 + max: 40 profiles: - xpath: ["authentication-key"] - autokey: + - name: autokey + type: string description: "Autokey Authentication" profiles: - xpath: ["autokey"] diff --git a/specs/network/interface/ethernet.yaml b/specs/network/interface/ethernet.yaml index 9e554242..16b40785 100644 --- a/specs/network/interface/ethernet.yaml +++ b/specs/network/interface/ethernet.yaml @@ -1,246 +1,291 @@ name: "Ethernet interface" terraform_provider_config: suffix: "ethernet_interface" -go_sdk_path: - - "network" - - "interface" - - "ethernet" +go_sdk_config: + package: + - "network" + - "interface" + - "ethernet" xpath_suffix: - "network" - "interface" - "ethernet" locations: - "ngfw": + - name: "ngfw" description: "Located in a specific NGFW." - device: - panorama: false - ngfw: true + devices: + - panorama + - ngfw xpath: - - "config" - - "devices" - - "{{ Entry $ngfw_device }}" - vars: - "ngfw_device": - description: "The NGFW device." - default: "localhost.localdomain" - "template": + path: + - "config" + - "devices" + - "$ngfw_device" + vars: + - name: "ngfw_device" + description: "The NGFW device." + default: "localhost.localdomain" + - name: "template" description: "Located in a specific template." - device: - panorama: true + devices: + - panorama xpath: - - "config" - - "devices" - - "{{ Entry $panorama_device }}" - - "template" - - "{{ Entry $template }}" - - "config" - - "devices" - - "{{ Entry $ngfw_device }}" - vars: - "panorama_device": - description: "The panorama device." - default: "localhost.localdomain" - "template": - description: "The template." - required: true - "ngfw_device": - description: "The NGFW device." - default: "localhost.localdomain" - "template-stack": + path: + - "config" + - "devices" + - "$panorama_device" + - "template" + - "$template" + - "config" + - "devices" + - "$ngfw_device" + vars: + - name: "panorama_device" + description: "The panorama device." + default: "localhost.localdomain" + - name: "template" + description: "The template." + required: true + - name: "ngfw_device" + description: "The NGFW device." + default: "localhost.localdomain" + - name: "template-stack" description: "Located in a specific template stack." - device: - panorama: true + devices: + - panorama xpath: - - "config" - - "devices" - - "{{ Entry $panorama_device }}" - - "template-stack" - - "{{ Entry $template_stack }}" - - "config" - - "devices" - - "{{ Entry $ngfw_device }}" - vars: - "panorama_device": - description: "The panorama device." - default: "localhost.localdomain" - "template_stack": - description: "The template stack." - required: true - "ngfw_device": - description: "The NGFW device." - default: "localhost.localdomain" -entry: - name: + path: + - "config" + - "devices" + - "$panorama_device" + - "template-stack" + - "$template_stack" + - "config" + - "devices" + - "$ngfw_device" + vars: + - name: "panorama_device" + description: "The panorama device." + default: "localhost.localdomain" + - name: "template_stack" + description: "The template stack." + required: true + - name: "ngfw_device" + description: "The NGFW device." + default: "localhost.localdomain" +entries: + - name: name description: "The name of the ethernet interface." + validators: + - type: length + spec: + min: 10 + max: 20 imports: - "template": + - name: template xpath: - - "config" - - "devices" - - "{{ Entry $ngfw_device }}" - - "vsys" - - "{{ Entry $vsys }}" - - "import" - - "network" - - "interfaces" - vars: - "ngfw_device": - description: "The NGFW device." - default: "localhost.localdomain" - "vsys": - description: "The vsys." - default: "vsys1" + path: + - "config" + - "devices" + - "$ngfw_device" + - "vsys" + - "$vsys" + - "import" + - "network" + - "interfaces" + vars: + - name: "ngfw_device" + description: "The NGFW device." + default: "localhost.localdomain" + - name: "vsys" + description: "The vsys." + default: "vsys1" only_for_params: - layer3 version: "10.1.0" spec: params: - comment: + - name: comment type: string - length: - min: 0 - max: 1023 + validators: + - type: length + spec: + min: 0 + max: 1023 profiles: - xpath: ["comment"] - link-state: - type: string - default: "auto" - values: ["auto", "up", "down"] + - name: link-state + type: enum profiles: - xpath: ["link-state"] - one_of: - tap: + validators: + - type: values + spec: + values: + - "auto" + - "up" + - "down" + spec: + values: + - value: "auto" + - value: "up" + - value: "down" + default: "auto" + variants: + - name: tap + type: object description: "Tap mode interface" profiles: - xpath: ["tap"] spec: params: - netflow-profile: + - name: netflow-profile type: string profiles: - xpath: ["netflow-profile"] - ha: + - name: ha + type: object description: "HA mode interface" profiles: - xpath: ["ha"] spec: - params: - layer3: + params: [] + - name: layer3 + type: object description: "Layer 3 interface" profiles: - xpath: ["layer3"] spec: params: - ndp-proxy: + - name: ndp-proxy type: bool profiles: - xpath: ["ndp-proxy", "enabled"] - lldp: + - name: lldp type: bool profiles: - xpath: ["lldp", "enable"] - mtu: + - name: mtu type: int64 description: "Maximum Transfer Unit, up to 9216 in Jumbo-Frame mode, up to 1500 otherwise" - value: - min: 576 - max: 9216 + validators: + - type: range + spec: + min: 576 + max: 9216 profiles: - xpath: ["mtu"] - ips: + - name: ips type: list description: "IP addresses or address objects names" - items: - type: string profiles: - type: entry xpath: ["ip"] - ipv6: + spec: + items: + type: string + - name: ipv6 + type: object profiles: - xpath: ["ipv6"] spec: params: - enabled: - type: bool - profiles: - - xpath: ["enabled"] - addresses: + - name: addresses type: list - items: - type: entry profiles: - type: entry xpath: ["address", "entry"] spec: - params: - enable-on-interface: - type: bool - profiles: - - xpath: ["enable-on-interface"] - dhcp-client: + items: + type: object + spec: + params: + - name: name + type: string + profiles: + - xpath: [] + spec: + required: true + - name: enable-on-interface + type: bool + profiles: + - xpath: ["enable-on-interface"] + - name: dhcp-client + type: object profiles: - xpath: ["dhcp-client"] spec: params: - enable: + - name: enable type: bool - default: true profiles: - xpath: ["enable"] - create-default-route: + spec: + default: true + - name: create-default-route type: bool - default: true + spec: + default: true profiles: - xpath: ["create-default-route"] - default-route-metric: + - name: default-route-metric type: int64 - default: 10 - value: - min: 1 - max: 65535 + spec: + default: 10 + validators: + - type: range + spec: + min: 1 + max: 65535 profiles: - xpath: ["default-route-metric"] - send-hostname: + - name: send-hostname + type: object profiles: - xpath: ["send-hostname"] spec: params: - enable: + - name: enable type: bool profiles: - xpath: ["enable"] - hostname: + - name: hostname type: string profiles: - xpath: ["hostname"] - interface-management-profile: + - name: interface-management-profile type: string profiles: - xpath: ["interface-management-profile"] - netflow-profile: + - name: netflow-profile type: string profiles: - xpath: ["netflow-profile"] - adjust-tcp-mss: + - name: adjust-tcp-mss + type: object profiles: - xpath: ["adjust-tcp-mss"] spec: params: - enable: + - name: enable type: bool profiles: - xpath: ["enable"] - ipv4-mss-adjustment: + - name: ipv4-mss-adjustment type: int64 - values: - min: 40 - max: 300 + validators: + - type: range + spec: + min: 40 + max: 300 profiles: - xpath: ["ipv4-mss-adjustment"] - ipv6-mss-adjustment: + - name: ipv6-mss-adjustment type: int64 - values: - min: 40 - max: 300 + validators: + - type: range + spec: + min: 40 + max: 300 profiles: - xpath: ["ipv6-mss-adjustment"] diff --git a/specs/network/interface/loopback.yaml b/specs/network/interface/loopback.yaml index 4f744865..48824cc4 100644 --- a/specs/network/interface/loopback.yaml +++ b/specs/network/interface/loopback.yaml @@ -1,154 +1,176 @@ -name: 'Loopback interface' +name: "Loopback interface" terraform_provider_config: - suffix: 'loopback_interface' -go_sdk_path: - - 'network' - - 'interface' - - 'loopback' + suffix: "loopback_interface" +go_sdk_config: + package: + - "network" + - "interface" + - "loopback" xpath_suffix: - - 'network' - - 'interface' - - 'loopback' - - 'units' + - "network" + - "interface" + - "loopback" + - "units" locations: - 'ngfw': - description: 'Located in a specific NGFW.' - device: - panorama: false - ngfw: true + - name: "ngfw" + description: "Located in a specific NGFW." + devices: + - panorama + - ngfw xpath: - - 'config' - - 'devices' - - '{{ Entry $ngfw_device }}' - vars: - 'ngfw_device': - description: 'The NGFW device.' - default: 'localhost.localdomain' - 'template': - description: 'Located in a specific template.' - device: - panorama: true + path: + - "config" + - "devices" + - "$ngfw_device" + vars: + - name: "ngfw_device" + description: "The NGFW device." + default: "localhost.localdomain" + - name: "template" + description: "Located in a specific template." + devices: + - panorama xpath: - - 'config' - - 'devices' - - '{{ Entry $panorama_device }}' - - 'template' - - '{{ Entry $template }}' - - 'config' - - 'devices' - - '{{ Entry $ngfw_device }}' - vars: - 'panorama_device': - description: 'The panorama device.' - default: 'localhost.localdomain' - 'template': - description: 'The template.' - required: true - 'ngfw_device': - description: 'The NGFW device.' - default: 'localhost.localdomain' - 'template-stack': - description: 'Located in a specific template stack.' - device: - panorama: true + path: + - "config" + - "devices" + - "$panorama_device" + - "template" + - "$template" + - "config" + - "devices" + - "$ngfw_device" + vars: + - name: "panorama_device" + description: "The panorama device." + default: "localhost.localdomain" + - name: "template" + description: "The template." + required: true + - name: "ngfw_device" + description: "The NGFW device." + default: "localhost.localdomain" + - name: "template-stack" + description: "Located in a specific template stack." + devices: + - panorama xpath: - - 'config' - - 'devices' - - '{{ Entry $panorama_device }}' - - 'template-stack' - - '{{ Entry $template_stack }}' - - 'config' - - 'devices' - - '{{ Entry $ngfw_device }}' - vars: - 'panorama_device': - description: 'The panorama device.' - default: 'localhost.localdomain' - 'template_stack': - description: 'The template stack.' - required: true - 'ngfw_device': - description: 'The NGFW device.' - default: 'localhost.localdomain' -entry: - name: - description: 'The name of the loopback interface.' -version: '10.1.0' + path: + - "config" + - "devices" + - "$panorama_device" + - "template-stack" + - "$template_stack" + - "config" + - "devices" + - "$ngfw_device" + vars: + - name: "panorama_device" + description: "The panorama device." + default: "localhost.localdomain" + - name: "template_stack" + description: "The template stack." + required: true + - name: "ngfw_device" + description: "The NGFW device." + default: "localhost.localdomain" +entries: + - name: name + description: "The name of the loopback interface." +version: "10.1.0" spec: params: - comment: + - name: comment type: string - length: - min: 0 - max: 1023 + validators: + - type: length + spec: + min: 0 + max: 1023 profiles: - - xpath: [ "comment" ] - mtu: + - xpath: ["comment"] + - name: mtu type: int64 description: "Maximum Transfer Unit, up to 9216 in Jumbo-Frame mode, up to 1500 otherwise" - value: - min: 576 - max: 9216 + validators: + - type: range + spec: + min: 576 + max: 9216 profiles: - - xpath: [ "mtu" ] - ips: + - xpath: ["mtu"] + - name: ips type: list description: "IP addresses or address objects names(netmask is not allowed for loopback)" - items: - type: string + spec: + items: + type: string profiles: - type: entry - xpath: [ "ip" ] - ipv6: + xpath: ["ip"] + - name: ipv6 + type: object profiles: - - xpath: [ "ipv6" ] + - xpath: ["ipv6"] spec: params: - enabled: + - name: enabled type: bool profiles: - - xpath: [ "enabled" ] - addresses: + - xpath: ["enabled"] + - name: addresses type: list - items: - type: entry profiles: - type: entry - xpath: [ "address", "entry" ] + xpath: ["address", "entry"] spec: - params: - enable-on-interface: - type: bool - profiles: - - xpath: [ "enable-on-interface" ] - interface-management-profile: + items: + type: object + spec: + params: + - name: name + type: string + profiles: + - xpath: [] + spec: + required: true + - name: enable-on-interface + type: bool + profiles: + - xpath: ["enable-on-interface"] + - name: interface-management-profile type: string profiles: - - xpath: [ "interface-management-profile" ] - netflow-profile: + - xpath: ["interface-management-profile"] + - name: netflow-profile type: string profiles: - - xpath: [ "netflow-profile" ] - adjust-tcp-mss: + - xpath: ["netflow-profile"] + - name: adjust-tcp-mss + type: object profiles: - - xpath: [ "adjust-tcp-mss" ] + - xpath: ["adjust-tcp-mss"] spec: params: - enable: + - name: enable type: bool profiles: - - xpath: [ "enable" ] - ipv4-mss-adjustment: + - xpath: ["enable"] + - name: ipv4-mss-adjustment type: int64 - values: - min: 40 - max: 300 + validators: + - type: range + spec: + min: 40 + max: 300 profiles: - - xpath: [ "ipv4-mss-adjustment" ] - ipv6-mss-adjustment: + - xpath: ["ipv4-mss-adjustment"] + - name: ipv6-mss-adjustment type: int64 - values: - min: 40 - max: 300 + validators: + - type: range + spec: + min: 40 + max: 300 profiles: - - xpath: [ "ipv6-mss-adjustment" ] + - xpath: ["ipv6-mss-adjustment"] diff --git a/specs/network/profiles/interface-management-profile.yaml b/specs/network/profiles/interface-management-profile.yaml index 18845ac5..5aa59002 100644 --- a/specs/network/profiles/interface-management-profile.yaml +++ b/specs/network/profiles/interface-management-profile.yaml @@ -1,128 +1,133 @@ -name: 'Interface management profile' +name: "Interface management profile" terraform_provider_config: - suffix: 'interface_management_profile' -go_sdk_path: - - 'network' - - 'profiles' - - 'interface_management' + suffix: "interface_management_profile" +go_sdk_config: + package: + - "network" + - "profiles" + - "interface_management" xpath_suffix: - - 'network' - - 'profiles' - - 'interface-management-profile' + - "network" + - "profiles" + - "interface-management-profile" locations: - 'ngfw': - description: 'Located in a specific NGFW.' - device: - panorama: false - ngfw: true + - name: "ngfw" + description: "Located in a specific NGFW." + devices: + - panorama + - ngfw xpath: - - 'config' - - 'devices' - - '{{ Entry $ngfw_device }}' - vars: - 'ngfw_device': - description: 'The NGFW device.' - default: 'localhost.localdomain' - 'template': - description: 'Located in a specific template.' - device: - panorama: true + path: + - "config" + - "devices" + - "$ngfw_device" + vars: + - name: ngfw_device + description: "The NGFW device." + default: "localhost.localdomain" + - name: "template" + description: "Located in a specific template." + devices: + - panorama xpath: - - 'config' - - 'devices' - - '{{ Entry $panorama_device }}' - - 'template' - - '{{ Entry $template }}' - - 'config' - - 'devices' - - '{{ Entry $ngfw_device }}' - vars: - 'panorama_device': - description: 'The panorama device.' - default: 'localhost.localdomain' - 'template': - description: 'The template.' - required: true - 'ngfw_device': - description: 'The NGFW device.' - default: 'localhost.localdomain' - 'template-stack': - description: 'Located in a specific template stack.' - device: - panorama: true + path: + - "config" + - "devices" + - "$panorama_device" + - "template" + - "$template" + - "config" + - "devices" + - "$ngfw_device" + vars: + - name: "panorama_device" + description: "The panorama device." + default: "localhost.localdomain" + - name: "template" + description: "The template." + required: true + - name: "ngfw_device" + description: "The NGFW device." + default: "localhost.localdomain" + - name: "template-stack" + description: "Located in a specific template stack." + devices: + - panorama xpath: - - 'config' - - 'devices' - - '{{ Entry $panorama_device }}' - - 'template-stack' - - '{{ Entry $template_stack }}' - - 'config' - - 'devices' - - '{{ Entry $ngfw_device }}' - vars: - 'panorama_device': - description: 'The panorama device.' - default: 'localhost.localdomain' - 'template_stack': - description: 'The template stack.' - required: true - 'ngfw_device': - description: 'The NGFW device.' - default: 'localhost.localdomain' -entry: - name: - description: 'The name of the interface management profile.' -version: '10.1.0' + path: + - "config" + - "devices" + - "$panorama_device" + - "template-stack" + - "$template_stack" + - "config" + - "devices" + - "$ngfw_device" + vars: + - name: "panorama_device" + description: "The panorama device." + default: "localhost.localdomain" + - name: "template_stack" + description: "The template stack." + required: true + - name: "ngfw_device" + description: "The NGFW device." + default: "localhost.localdomain" +entries: + - name: name + description: "The name of the interface management profile." +version: "10.1.0" spec: params: - http: + - name: http type: bool profiles: - - xpath: [ "http" ] - https: + - xpath: ["http"] + - name: https type: bool profiles: - - xpath: [ "https" ] - ping: + - xpath: ["https"] + - name: ping type: bool profiles: - - xpath: [ "ping" ] - response-pages: + - xpath: ["ping"] + - name: response-pages type: bool profiles: - - xpath: [ "response-pages" ] - userid-service: + - xpath: ["response-pages"] + - name: userid-service type: bool profiles: - - xpath: [ "userid-service" ] - userid-syslog-listener-ssl: + - xpath: ["userid-service"] + - name: userid-syslog-listener-ssl type: bool profiles: - - xpath: [ "userid-syslog-listener-ssl" ] - userid-syslog-listener-udp: + - xpath: ["userid-syslog-listener-ssl"] + - name: userid-syslog-listener-udp type: bool profiles: - - xpath: [ "userid-syslog-listener-udp" ] - ssh: + - xpath: ["userid-syslog-listener-udp"] + - name: ssh type: bool profiles: - - xpath: [ "ssh" ] - telnet: + - xpath: ["ssh"] + - name: telnet type: bool profiles: - - xpath: [ "telnet" ] - snmp: + - xpath: ["telnet"] + - name: snmp type: bool profiles: - - xpath: [ "snmp" ] - http-ocsp: + - xpath: ["snmp"] + - name: http-ocsp type: bool profiles: - - xpath: [ "http-ocsp" ] - permitted-ips: + - xpath: ["http-ocsp"] + - name: permitted-ips type: list - items: - type: string + spec: + items: + type: string profiles: - type: entry - xpath: [ "permitted-ip" ] + xpath: ["permitted-ip"] diff --git a/specs/network/virtual-router.yaml b/specs/network/virtual-router.yaml index 6d98ab58..66fa09f5 100644 --- a/specs/network/virtual-router.yaml +++ b/specs/network/virtual-router.yaml @@ -1,395 +1,453 @@ -name: 'Virtual router' +name: "Virtual router" terraform_provider_config: - suffix: 'virtual_router' -go_sdk_path: - - 'network' - - 'virtual_router' + suffix: "virtual_router" +go_sdk_config: + package: + - "network" + - "virtual_router" xpath_suffix: - - 'network' - - 'virtual-router' + - "network" + - "virtual-router" locations: - 'ngfw': - description: 'Located in a specific NGFW.' - device: - panorama: false - ngfw: true + - name: "ngfw" + description: "Located in a specific NGFW." + devices: + - panorama + - ngfw xpath: - - 'config' - - 'devices' - - '{{ Entry $ngfw_device }}' - vars: - 'ngfw_device': - description: 'The NGFW device.' - default: 'localhost.localdomain' - 'template': - description: 'Located in a specific template.' - device: - panorama: true + path: + - "config" + - "devices" + - "$ngfw_device" + vars: + - name: "ngfw_device" + description: "The NGFW device." + default: "localhost.localdomain" + - name: "template" + description: "Located in a specific template." + devices: + - panorama xpath: - - 'config' - - 'devices' - - '{{ Entry $panorama_device }}' - - 'template' - - '{{ Entry $template }}' - - 'config' - - 'devices' - - '{{ Entry $ngfw_device }}' - vars: - 'panorama_device': - description: 'The panorama device.' - default: 'localhost.localdomain' - 'template': - description: 'The template.' - required: true - 'ngfw_device': - description: 'The NGFW device.' - default: 'localhost.localdomain' - 'template-stack': - description: 'Located in a specific template stack.' - device: - panorama: true + path: + - "config" + - "devices" + - "$panorama_device" + - "template" + - "$template" + - "config" + - "devices" + - "$ngfw_device" + vars: + - name: "panorama_device" + description: "The panorama device." + default: "localhost.localdomain" + - name: "template" + description: "The template." + required: true + - name: "ngfw_device" + description: "The NGFW device." + default: "localhost.localdomain" + - name: "template-stack" + description: "Located in a specific template stack." + devices: + - panorama xpath: - - 'config' - - 'devices' - - '{{ Entry $panorama_device }}' - - 'template-stack' - - '{{ Entry $template_stack }}' - - 'config' - - 'devices' - - '{{ Entry $ngfw_device }}' - vars: - 'panorama_device': - description: 'The panorama device.' - default: 'localhost.localdomain' - 'template_stack': - description: 'The template stack.' - required: true - 'ngfw_device': - description: 'The NGFW device.' - default: 'localhost.localdomain' -entry: - name: - description: 'The name of the virtual router.' -version: '10.1.0' + path: + - "config" + - "devices" + - "$panorama_device" + - "template-stack" + - "$template_stack" + - "config" + - "devices" + - "$ngfw_device" + vars: + - name: "panorama_device" + description: "The panorama device." + default: "localhost.localdomain" + - name: "template_stack" + description: "The template stack." + required: true + - name: "ngfw_device" + description: "The NGFW device." + default: "localhost.localdomain" +entries: + - name: name + description: "The name of the virtual router." +version: "10.1.0" spec: params: - interfaces: + - name: interfaces type: list - items: - type: string + spec: + items: + type: string profiles: - - xpath: [ "interface" ] + - xpath: ["interface"] type: member - routing-table: + - name: routing-table + type: object profiles: - - xpath: [ "routing-table" ] + - xpath: ["routing-table"] spec: params: - ip: + - name: ip + type: object profiles: - - xpath: [ "ip" ] + - xpath: ["ip"] spec: params: - static-routes: + - name: static-routes type: list - items: - type: entry profiles: - - xpath: [ "static-route", "entry" ] + - xpath: ["static-route", "entry"] type: entry spec: - params: - destination: - type: string - profiles: - - xpath: [ "destination" ] - interface: - type: string - profiles: - - xpath: [ "interface" ] - next-hop: - profiles: - - xpath: [ "nexthop" ] - spec: - params: - ip-address: - type: string - profiles: - - xpath: [ "ip-address" ] - fqdn: - type: string - profiles: - - xpath: [ "fqdn" ] - next-vr: - type: string - profiles: - - xpath: [ "next-vr" ] - tunnel: - type: string - profiles: - - xpath: [ "tunnel" ] - admin-dist: - type: int64 - profiles: - - xpath: [ "admin-dist" ] - metric: - type: int64 - profiles: - - xpath: [ "metric" ] - route-table: - type: string - profiles: - - xpath: [ "route-table" ] - ipv6: + items: + type: object + spec: + params: + - name: destination + type: string + profiles: + - xpath: ["destination"] + - name: interface + type: string + profiles: + - xpath: ["interface"] + - name: next-hop + type: object + profiles: + - xpath: ["nexthop"] + spec: + params: + - name: ip-address + type: string + profiles: + - xpath: ["ip-address"] + - name: fqdn + type: string + profiles: + - xpath: ["fqdn"] + - name: next-vr + type: string + profiles: + - xpath: ["next-vr"] + - name: tunnel + type: string + profiles: + - xpath: ["tunnel"] + - name: admin-dist + type: int64 + profiles: + - xpath: ["admin-dist"] + - name: metric + type: int64 + profiles: + - xpath: ["metric"] + - name: route-table + type: string + profiles: + - xpath: ["route-table"] + - name: ipv6 + type: object profiles: - - xpath: [ "ipv6" ] + - xpath: ["ipv6"] spec: params: - static-routes: + - name: static-routes type: list - items: - type: entry profiles: - - xpath: [ "static-route", "entry" ] + - xpath: ["static-route", "entry"] type: entry spec: - params: - destination: - type: string - profiles: - - xpath: [ "destination" ] - interface: - type: string - profiles: - - xpath: [ "interface" ] - next-hop: - profiles: - - xpath: [ "nexthop" ] - spec: - params: - ipv6-address: - type: string - profiles: - - xpath: [ "ipv6-address" ] - fqdn: - type: string - profiles: - - xpath: [ "fqdn" ] - next-vr: - type: string - profiles: - - xpath: [ "next-vr" ] - tunnel: - type: string - profiles: - - xpath: [ "tunnel" ] - admin-dist: - type: int64 - profiles: - - xpath: [ "admin-dist" ] - metric: - type: int64 - profiles: - - xpath: [ "metric" ] - route-table: - type: string - profiles: - - xpath: [ "route-table" ] - protocol: + items: + type: object + spec: + params: + - name: destination + type: string + profiles: + - xpath: ["destination"] + - name: interface + type: string + profiles: + - xpath: ["interface"] + - name: next-hop + type: object + profiles: + - xpath: ["nexthop"] + spec: + params: + - name: ipv6-address + type: string + profiles: + - xpath: ["ipv6-address"] + - name: fqdn + type: string + profiles: + - xpath: ["fqdn"] + - name: next-vr + type: string + profiles: + - xpath: ["next-vr"] + - name: tunnel + type: string + profiles: + - xpath: ["tunnel"] + - name: admin-dist + type: int64 + profiles: + - xpath: ["admin-dist"] + - name: metric + type: int64 + profiles: + - xpath: ["metric"] + - name: route-table + type: string + profiles: + - xpath: ["route-table"] + - name: protocol + type: object profiles: - - xpath: [ "protocol" ] + - xpath: ["protocol"] spec: params: - bgp: + - name: bgp + type: object profiles: - - xpath: [ "bgp" ] + - xpath: ["bgp"] spec: params: - enable: + - name: enable type: bool profiles: - - xpath: [ "enable" ] - rip: + - xpath: ["enable"] + - name: rip + type: object profiles: - - xpath: [ "rip" ] + - xpath: ["rip"] spec: params: - enable: + - name: enable type: bool profiles: - - xpath: [ "enable" ] - ospf: + - xpath: ["enable"] + - name: ospf + type: object profiles: - - xpath: [ "ospf" ] + - xpath: ["ospf"] spec: params: - enable: + - name: enable type: bool profiles: - - xpath: [ "enable" ] - ospfv3: + - xpath: ["enable"] + - name: ospfv3 + type: object profiles: - - xpath: [ "ospfv3" ] + - xpath: ["ospfv3"] spec: params: - enable: + - name: enable type: bool profiles: - - xpath: [ "enable" ] - ecmp: + - xpath: ["enable"] + - name: ecmp + type: object profiles: - - xpath: [ "ecmp" ] + - xpath: ["ecmp"] spec: params: - enable: + - name: enable type: bool profiles: - - xpath: [ "enable" ] - symmetric-return: + - xpath: ["enable"] + - name: symmetric-return type: bool profiles: - - xpath: [ "symmetric-return" ] - strict-source-path: + - xpath: ["symmetric-return"] + - name: strict-source-path type: bool profiles: - - xpath: [ "strict-source-path" ] - max-paths: + - xpath: ["strict-source-path"] + - name: max-paths type: int64 - value: - min: 2 - max: 4 + validators: + - type: range + spec: + min: 2 + max: 4 profiles: - - xpath: [ "max-path" ] - algorithm: + - xpath: ["max-path"] + - name: algorithm + type: object profiles: - - xpath: [ "algorithm" ] + - xpath: ["algorithm"] spec: params: - ip-modulo: + - name: ip-modulo + type: object profiles: - - xpath: [ "ip-modulo" ] + - xpath: ["ip-modulo"] spec: - params: - ip-hash: + params: [] + - name: ip-hash + type: object profiles: - - xpath: [ "ip-hash" ] + - xpath: ["ip-hash"] spec: params: - src-only: + - name: src-only type: bool profiles: - - xpath: [ "src-only" ] - use-port: + - xpath: ["src-only"] + - name: use-port type: bool profiles: - - xpath: [ "use-port" ] - hash-seed: + - xpath: ["use-port"] + - name: hash-seed type: int64 - value: - min: 0 - max: 4294967295 + validators: + - type: range + spec: + min: 0 + max: 4294967295 profiles: - - xpath: [ "hash-seed" ] - weighted-round-robin: + - xpath: ["hash-seed"] + - name: weighted-round-robin + type: object profiles: - - xpath: [ "weighted-round-robin" ] + - xpath: ["weighted-round-robin"] spec: params: - interfaces: + - name: interfaces type: list - items: - type: entry profiles: - - xpath: [ "interface", "entry" ] + - xpath: ["interface", "entry"] type: entry spec: - params: - weight: - type: int64 - value: - min: 1 - max: 255 - profiles: - - xpath: [ "weight" ] - balanced-round-robin: + items: + type: object + spec: + params: + - name: weight + type: int64 + validators: + - type: range + spec: + min: 1 + max: 255 + profiles: + - xpath: ["weight"] + - name: balanced-round-robin + type: object profiles: - - xpath: [ "balanced-round-robin" ] + - xpath: ["balanced-round-robin"] spec: - params: - administrative-distances: + params: [] + - name: administrative-distances + type: object profiles: - - xpath: [ "admin-dists" ] + - xpath: ["admin-dists"] spec: params: - static: + - name: static type: int64 - default: 10 - value: - min: 10 - max: 240 + spec: + default: 10 + validators: + - type: range + spec: + min: 10 + max: 240 profiles: - - xpath: [ "static" ] - static-ipv6: + - xpath: ["static"] + - name: static-ipv6 type: int64 - default: 10 - value: - min: 10 - max: 240 + spec: + default: 10 + validators: + - type: range + spec: + min: 10 + max: 240 profiles: - - xpath: [ "static-ipv6" ] - ospf-int: + - xpath: ["static-ipv6"] + - name: ospf-int type: int64 - default: 30 - value: - min: 10 - max: 240 + spec: + default: 30 + validators: + - type: range + spec: + min: 10 + max: 240 profiles: - - xpath: [ "ospf-int" ] - ospf-ext: + - xpath: ["ospf-int"] + - name: ospf-ext type: int64 - default: 110 - value: - min: 10 - max: 240 + spec: + default: 110 + validators: + - type: range + spec: + min: 10 + max: 240 profiles: - - xpath: [ "ospf-ext" ] - ospfv3-int: + - xpath: ["ospf-ext"] + - name: ospfv3-int type: int64 - default: 30 - value: - min: 10 - max: 240 + spec: + default: 30 + validators: + - type: range + spec: + min: 10 + max: 240 profiles: - - xpath: [ "ospfv3-int" ] - ospfv3-ext: + - xpath: ["ospfv3-int"] + - name: ospfv3-ext type: int64 - default: 110 - value: - min: 10 - max: 240 + spec: + default: 110 + validators: + - type: range + spec: + min: 10 + max: 240 profiles: - - xpath: [ "ospfv3-ext" ] - ibgp: + - xpath: ["ospfv3-ext"] + - name: ibgp type: int64 - default: 200 - value: - min: 10 - max: 240 + spec: + default: 200 + validators: + - type: range + spec: + min: 10 + max: 240 profiles: - - xpath: [ "ibgp" ] - ebgp: + - xpath: ["ibgp"] + - name: ebgp type: int64 - default: 20 - value: - min: 10 - max: 240 + spec: + default: 20 + validators: + - type: range + spec: + min: 10 + max: 240 profiles: - - xpath: [ "ebgp" ] - rip: + - xpath: ["ebgp"] + - name: rip type: int64 - default: 120 - value: - min: 10 - max: 240 + spec: + default: 120 + validators: + - type: range + spec: + min: 10 + max: 240 profiles: - - xpath: [ "rip" ] + - xpath: ["rip"] diff --git a/specs/network/zone.yaml b/specs/network/zone.yaml index fe50559e..f118385b 100644 --- a/specs/network/zone.yaml +++ b/specs/network/zone.yaml @@ -1,214 +1,245 @@ -name: 'Zone' +name: "Zone" terraform_provider_config: - suffix: 'zone' -go_sdk_path: - - 'network' - - 'zone' + suffix: "zone" +go_sdk_config: + package: + - "network" + - "zone" xpath_suffix: - - 'zone' + - "zone" locations: - 'vsys': - description: 'Located in a specific vsys.' - device: - panorama: false - ngfw: true + - name: "vsys" + description: "Located in a specific vsys." + devices: + - panorama + - ngfw xpath: - - 'config' - - 'devices' - - '{{ Entry $ngfw_device }}' - - 'vsys' - - '{{ Entry $vsys }}' - vars: - 'ngfw_device': - description: 'The NGFW device.' - default: 'localhost.localdomain' - 'vsys': - description: 'The vsys.' - default: 'vsys1' - validation: - not_values: - 'shared': 'The vsys cannot be "shared". Use the "shared" path instead.' - 'from_panorama_vsys': - description: 'Located in a specific vsys in the config pushed from Panorama.' + path: + - "config" + - "devices" + - "$ngfw_device" + - "vsys" + - "$vsys" + vars: + - name: "ngfw_device" + description: "The NGFW device." + default: "localhost.localdomain" + - name: "vsys" + description: "The vsys." + default: "vsys1" + validators: + - type: not-values + spec: + values: + - value: shared + error: 'The vsys cannot be "shared". Use the "shared" path instead.' + - name: "from_panorama_vsys" + description: "Located in a specific vsys in the config pushed from Panorama." read_only: true - device: - ngfw: true + devices: + - ngfw xpath: - - 'config' - - 'panorama' - - 'vsys' - - '{{ Entry $vsys }}' - vars: - 'vsys': - description: 'The vsys.' - default: 'vsys1' - validation: - not_values: - 'shared': 'The vsys cannot be "shared". Use the "shared" path instead.' - 'template': - description: 'Located in a specific template.' - device: - panorama: true + path: + - "config" + - "panorama" + - "vsys" + - "$vsys" + vars: + - name: "vsys" + description: "The vsys." + default: "vsys1" + validators: + - type: not-values + spec: + values: + - value: "shared" + error: 'The vsys cannot be "shared". Use the "shared" path instead.' + - name: "template" + description: "Located in a specific template." + devices: + - panorama xpath: - - 'config' - - 'devices' - - '{{ Entry $panorama_device }}' - - 'template' - - '{{ Entry $template }}' - - 'config' - - 'devices' - - '{{ Entry $ngfw_device }}' - - 'vsys' - - '{{ Entry $vsys }}' - vars: - 'panorama_device': - description: 'The panorama device.' - default: 'localhost.localdomain' - 'template': - description: 'The template.' - required: true - 'ngfw_device': - description: 'The NGFW device.' - default: 'localhost.localdomain' - 'vsys': - description: 'The vsys.' - default: 'vsys1' - validation: - not_values: - 'shared': 'The vsys cannot be "shared". Use the "shared" path instead.' - 'template-stack': - description: 'Located in a specific template stack.' - device: - panorama: true + path: + - "config" + - "devices" + - "$panorama_device" + - "template" + - "$template" + - "config" + - "devices" + - "$ngfw_device" + - "vsys" + - "$vsys" + vars: + - name: "panorama_device" + description: "The panorama device." + default: "localhost.localdomain" + - name: "template" + description: "The template." + required: true + - name: "ngfw_device" + description: "The NGFW device." + default: "localhost.localdomain" + - name: "vsys" + description: "The vsys." + default: "vsys1" + validators: + - type: not-values + spec: + values: + - value: "shared" + error: 'The vsys cannot be "shared". Use the "shared" path instead.' + - name: "template-stack" + description: "Located in a specific template stack." + devices: + - panorama xpath: - - 'config' - - 'devices' - - '{{ Entry $panorama_device }}' - - 'template-stack' - - '{{ Entry $template_stack }}' - - 'config' - - 'devices' - - '{{ Entry $ngfw_device }}' - - 'vsys' - - '{{ Entry $vsys }}' - vars: - 'panorama_device': - description: 'The panorama device.' - default: 'localhost.localdomain' - 'template_stack': - description: 'The template stack.' - required: true - 'ngfw_device': - description: 'The NGFW device.' - default: 'localhost.localdomain' - 'vsys': - description: 'The vsys.' - default: 'vsys1' - validation: - not_values: - 'shared': 'The vsys cannot be "shared". Use the "shared" path instead.' -entry: - name: - description: 'The name of the zone.' -version: '10.1.0' + path: + - "config" + - "devices" + - "$panorama_device" + - "template-stack" + - "$template_stack" + - "config" + - "devices" + - "$ngfw_device" + - "vsys" + - "$vsys" + vars: + - name: "panorama_device" + description: "The panorama device." + default: "localhost.localdomain" + - name: "template_stack" + description: "The template stack." + required: true + - name: "ngfw_device" + description: "The NGFW device." + default: "localhost.localdomain" + - name: "vsys" + description: "The vsys." + default: "vsys1" + validators: + - type: not-values + spec: + values: + - value: "shared" + error: 'The vsys cannot be "shared". Use the "shared" path instead.' +entries: + - name: name + description: "The name of the zone." +version: "10.1.0" spec: params: - enable-user-identification: + - name: enable-user-identification type: bool profiles: - - xpath: [ "enable-user-identification" ] - enable-device-identification: + - xpath: ["enable-user-identification"] + - name: enable-device-identification type: bool profiles: - - xpath: [ "enable-device-identification" ] - user-acl: + - xpath: ["enable-device-identification"] + - name: user-acl + type: object profiles: - - xpath: [ "user-acl" ] + - xpath: ["user-acl"] spec: params: - include-list: + - name: include-list type: list - items: - type: string + spec: + items: + type: string profiles: - - xpath: [ "include-list" ] + - xpath: ["include-list"] type: member - exclude-list: + - name: exclude-list type: list - items: - type: string + spec: + items: + type: string profiles: - - xpath: [ "exclude-list" ] + - xpath: ["exclude-list"] type: member - device-acl: + - name: device-acl + type: object profiles: - - xpath: [ "device-acl" ] + - xpath: ["device-acl"] spec: params: - include-list: + - name: include-list type: list - items: - type: string + spec: + items: + type: string profiles: - - xpath: [ "include-list" ] + - xpath: ["include-list"] type: member - exclude-list: + - name: exclude-list type: list - items: - type: string + spec: + items: + type: string profiles: - - xpath: [ "exclude-list" ] + - xpath: ["exclude-list"] type: member - network: + - name: network + type: object profiles: - - xpath: [ "network" ] + - xpath: ["network"] spec: params: - enable-packet-buffer-protection: + - name: enable-packet-buffer-protection type: bool - default: true + spec: + default: true profiles: - - xpath: [ "enable-packet-buffer-protection" ] - zone-protection-profile: + - xpath: ["enable-packet-buffer-protection"] + - name: zone-protection-profile type: list - items: - type: string + spec: + items: + type: string profiles: - - xpath: [ "zone-protection-profile" ] + - xpath: ["zone-protection-profile"] type: member - log-setting: + - name: log-setting type: list - items: - type: string + spec: + items: + type: string profiles: - - xpath: [ "log-setting" ] + - xpath: ["log-setting"] type: member - one_of: - layer3: + variants: + - name: layer3 type: list - items: - type: string + spec: + items: + type: string profiles: - - xpath: [ "layer3" ] + - xpath: ["layer3"] type: member - layer2: + - name: layer2 type: list - items: - type: string + spec: + items: + type: string profiles: - - xpath: [ "layer2" ] + - xpath: ["layer2"] type: member - virtual-wire: + - name: virtual-wire type: list - items: - type: string + spec: + items: + type: string profiles: - - xpath: [ "virtual-wire" ] + - xpath: ["virtual-wire"] type: member - tap: + - name: tap type: list - items: - type: string + spec: + items: + type: string profiles: - - xpath: [ "tap" ] + - xpath: ["tap"] type: member diff --git a/specs/objects/address-group.yaml b/specs/objects/address-group.yaml index 3e7611c1..52f4603b 100644 --- a/specs/objects/address-group.yaml +++ b/specs/objects/address-group.yaml @@ -1,131 +1,158 @@ -name: 'Address group' +name: "Address group" terraform_provider_config: - suffix: 'address_group' -go_sdk_path: - - 'objects' - - 'address' - - 'group' + suffix: "address_group" +go_sdk_config: + package: + - "objects" + - "address" + - "group" xpath_suffix: - - 'address-group' + - "address-group" locations: - 'shared': - description: 'Located in shared.' - device: - panorama: true - ngfw: true - xpath: ['config', 'shared'] - 'vsys': - description: 'Located in a specific vsys.' - device: - panorama: true - ngfw: true + - name: "shared" + description: "Located in shared." + devices: + - panorama + - ngfw xpath: - - 'config' - - 'devices' - - '{{ Entry $ngfw_device }}' - - 'vsys' - - '{{ Entry $vsys }}' - vars: - 'ngfw_device': - description: 'The NGFW device.' - default: 'localhost.localdomain' - 'vsys': - description: 'The vsys.' - default: 'vsys1' - validation: - not_values: - 'shared': 'The vsys cannot be "shared". Use the "shared" path instead.' - 'from_panorama_shared': - description: 'Located in shared in the config pushed from Panorama.' + path: ["config", "shared"] + - name: "vsys" + description: "Located in a specific vsys." + devices: + - panorama + - ngfw + xpath: + path: + - "config" + - "devices" + - "$ngfw_device" + - "vsys" + - "$vsys" + vars: + - name: "ngfw_device" + description: "The NGFW device." + default: "localhost.localdomain" + - name: "vsys" + description: "The vsys." + default: "vsys1" + validators: + - type: not-values + spec: + values: + - value: "shared" + error: 'The vsys cannot be "shared". Use the "shared" path instead.' + - name: "from_panorama_shared" + description: "Located in shared in the config pushed from Panorama." read_only: true - device: - ngfw: true + devices: + - ngfw xpath: - - 'config' - - 'panorama' - - 'shared' - 'from_panorama_vsys': - description: 'Located in a specific vsys in the config pushed from Panorama.' + path: + - "config" + - "panorama" + - "shared" + - name: "from_panorama_vsys" + description: "Located in a specific vsys in the config pushed from Panorama." read_only: true - device: - ngfw: true + devices: + - ngfw xpath: - - 'config' - - 'panorama' - - 'vsys' - - '{{ Entry $vsys }}' - vars: - 'vsys': - description: 'The vsys.' - default: 'vsys1' - validation: - not_values: - 'shared': 'The vsys cannot be "shared". Use the "shared" path instead.' - 'device_group': - description: 'Located in a specific device group.' - device: - panorama: true + path: + - "config" + - "panorama" + - "vsys" + - "$vsys" + vars: + - name: "vsys" + description: "The vsys." + default: "vsys1" + validators: + - type: not-values + spec: + values: + - value: "shared" + error: 'The vsys cannot be "shared". Use the "shared" path instead.' + - name: "device_group" + description: "Located in a specific device group." + devices: + - panorama xpath: - - 'config' - - 'devices' - - '{{ Entry $panorama_device }}' - - 'device-group' - - '{{ Entry $device_group }}' - vars: - 'panorama_device': - description: 'The panorama device.' - default: 'localhost.localdomain' - 'device_group': - description: 'The device group.' - required: true - validation: - not_values: - 'shared': 'The device group cannot be "shared". Use the "shared" path instead.' -entry: - name: - description: 'The name of the address group.' - length: - min: 1 - max: 63 -version: '10.1.0' + path: + - "config" + - "devices" + - "$panorama_device" + - "device-group" + - "$device_group" + vars: + - name: "panorama_device" + description: "The panorama device." + default: "localhost.localdomain" + - name: "device_group" + description: "The device group." + required: true + validators: + - type: not-values + spec: + values: + - value: "shared" + error: 'The device group cannot be "shared". Use the "shared" path instead.' +entries: + - name: name + description: "The name of the address group." + validators: + - type: length + spec: + min: 1 + max: 63 +version: "10.1.0" spec: params: - description: - description: 'The description.' + - name: description + description: "The description." type: string - length: - min: 0 - max: 1023 profiles: - - - xpath: ["description"] - tags: - description: 'The administrative tags.' + - xpath: ["description"] + validators: + - type: length + spec: + min: 0 + max: 1023 + - name: tags + description: "The administrative tags." type: list - count: - max: 64 - items: - type: string - length: - max: 127 profiles: - - - type: member + - type: member xpath: ["tag"] - one_of: - 'static': + validators: + - type: count + spec: + max: 64 + spec: + items: + type: string + validators: + - type: length + spec: + max: 127 + variants: + - name: "static" type: list - count: - min: 1 - items: - type: string profiles: - - xpath: [ "static" ] + - xpath: ["static"] type: member - 'dynamic': - length: - min: 1 - max: 2047 + validators: + - type: count + spec: + min: 1 + spec: + items: + type: string + - name: "dynamic" + type: string # FIXME: the original spec made no sense + validators: + - type: length + spec: + min: 1 + max: 2047 profiles: - - - xpath: ["dynamic/filter"] + - xpath: ["dynamic", "filter"] # FIXME: original xpath dynamic/filter made no sense diff --git a/specs/objects/address.yaml b/specs/objects/address.yaml index dde1244a..96ba445c 100644 --- a/specs/objects/address.yaml +++ b/specs/objects/address.yaml @@ -1,138 +1,164 @@ -name: 'Address' +name: "Address" terraform_provider_config: - suffix: 'address_object' -go_sdk_path: - - 'objects' - - 'address' + suffix: "address_object" +go_sdk_config: + package: + - "objects" + - "address" xpath_suffix: - - 'address' + - "address" locations: - 'shared': - description: 'Located in shared.' - device: - panorama: true - ngfw: true - xpath: ['config', 'shared'] - 'vsys': - description: 'Located in a specific vsys.' - device: - panorama: true - ngfw: true + - name: "shared" + description: "Located in shared." + devices: + - panorama + - ngfw xpath: - - 'config' - - 'devices' - - '{{ Entry $ngfw_device }}' - - 'vsys' - - '{{ Entry $vsys }}' - vars: - 'ngfw_device': - description: 'The NGFW device.' - default: 'localhost.localdomain' - 'vsys': - description: 'The vsys.' - default: 'vsys1' - validation: - not_values: - 'shared': 'The vsys cannot be "shared". Use the "shared" path instead.' - 'from_panorama_shared': - description: 'Located in shared in the config pushed from Panorama.' + path: ["config", "shared"] + - name: "vsys" + description: "Located in a specific vsys." + devices: + - panorama + - ngfw + xpath: + path: + - "config" + - "devices" + - "$ngfw_device" + - "vsys" + - "$vsys" + vars: + - name: "ngfw_device" + description: "The NGFW device." + default: "localhost.localdomain" + - name: "vsys" + description: "The vsys." + default: "vsys1" + validators: + - type: not-values + spec: + values: + - value: invalid + error: 'The vsys cannot be "shared". Use the "shared" path instead.' + - name: "from_panorama_shared" + description: "Located in shared in the config pushed from Panorama." read_only: true - device: - ngfw: true + devices: + - ngfw xpath: - - 'config' - - 'panorama' - - 'shared' - 'from_panorama_vsys': - description: 'Located in a specific vsys in the config pushed from Panorama.' + path: + - "config" + - "panorama" + - "shared" + - name: "from_panorama_vsys" + description: "Located in a specific vsys in the config pushed from Panorama." read_only: true - device: - ngfw: true + devices: + - ngfw xpath: - - 'config' - - 'panorama' - - 'vsys' - - '{{ Entry $vsys }}' - vars: - 'vsys': - description: 'The vsys.' - default: 'vsys1' - validation: - not_values: - 'shared': 'The vsys cannot be "shared". Use the "shared" path instead.' - 'device_group': - description: 'Located in a specific device group.' - device: - panorama: true + path: + - "config" + - "panorama" + - "vsys" + - "$vsys" + vars: + - name: "vsys" + description: "The vsys." + default: "vsys1" + validators: + - type: not-values + spec: + values: + - value: "shared" + error: 'The vsys cannot be "shared". Use the "shared" path instead.' + - name: "device_group" + description: "Located in a specific device group." + devices: + - panorama xpath: - - 'config' - - 'devices' - - '{{ Entry $panorama_device }}' - - 'device-group' - - '{{ Entry $device_group }}' - vars: - 'panorama_device': - description: 'The panorama device.' - default: 'localhost.localdomain' - 'device_group': - description: 'The device group.' - required: true - validation: - not_values: - 'shared': 'The device group cannot be "shared". Use the "shared" path instead.' -entry: - name: - description: 'The name of the address object.' - length: - min: 1 - max: 63 -version: '10.1.0' + path: + - "config" + - "devices" + - "$panorama_device" + - "device-group" + - "$device_group" + vars: + - name: "panorama_device" + description: "The panorama device." + default: "localhost.localdomain" + - name: "device_group" + description: "The device group." + required: true + validators: + - type: not-values + spec: + values: + - value: "shared" + error: 'The device group cannot be "shared". Use the "shared" path instead.' +entries: + - name: name + description: "The name of the address object." + validators: + - type: length + spec: + min: 1 + max: 63 +version: "10.1.0" spec: params: - description: - description: 'The description.' + - name: description + description: "The description." type: string - length: - min: 0 - max: 1023 + validators: + - type: length + spec: + min: 0 + max: 1023 profiles: - - - xpath: ["description"] - tags: - description: 'The administrative tags.' + - xpath: ["description"] + - name: tags + description: "The administrative tags." type: list - count: - max: 64 - items: - type: string - length: - max: 127 + validators: + - type: count + spec: + max: 64 + spec: + items: + type: string + validators: + - type: length + spec: + max: 127 profiles: - - - type: member + - type: member xpath: ["tag"] - one_of: - 'ip_netmask': - description: 'The IP netmask value.' + variants: + - name: "ip_netmask" + type: string + description: "The IP netmask value." profiles: - - - xpath: ["ip-netmask"] - 'ip_range': - description: 'The IP range value.' + - xpath: ["ip-netmask"] + - name: "ip_range" + type: string + description: "The IP range value." profiles: - - - xpath: ["ip-range"] - 'fqdn': - description: 'The FQDN value.' - regex: '^[a-zA-Z0-9_]([a-zA-Z0-9:_-])+[a-zA-Z0-9]$' - length: - min: 1 - max: 255 + - xpath: ["ip-range"] + - name: "fqdn" + type: string + description: "The FQDN value." + validators: + - type: regexp + spec: + expr: "^[a-zA-Z0-9_]([a-zA-Z0-9:_-])+[a-zA-Z0-9]$" + - type: length + spec: + min: 1 + max: 255 profiles: - - - xpath: ["fqdn"] - 'ip_wildcard': - description: 'The IP wildcard value.' + - xpath: ["fqdn"] + - name: "ip_wildcard" + type: string + description: "The IP wildcard value." profiles: - - - xpath: ["ip-wildcard"] + - xpath: ["ip-wildcard"] diff --git a/specs/objects/service-group.yaml b/specs/objects/service-group.yaml index ad676067..c1f3e1c2 100644 --- a/specs/objects/service-group.yaml +++ b/specs/objects/service-group.yaml @@ -1,124 +1,149 @@ -name: 'Service group' +name: "Service group" terraform_provider_config: - suffix: 'service_group' -go_sdk_path: - - 'objects' - - 'service' - - 'group' + suffix: "service_group" +go_sdk_config: + package: + - "objects" + - "service" + - "group" xpath_suffix: - - 'service-group' + - "service-group" locations: - 'shared': - description: 'Located in shared.' - device: - panorama: true - ngfw: true - xpath: ['config', 'shared'] - 'vsys': - description: 'Located in a specific vsys.' - device: - panorama: true - ngfw: true + - name: "shared" + description: "Located in shared." + devices: + - panorama + - ngfw xpath: - - 'config' - - 'devices' - - '{{ Entry $ngfw_device }}' - - 'vsys' - - '{{ Entry $vsys }}' - vars: - 'ngfw_device': - description: 'The NGFW device.' - default: 'localhost.localdomain' - 'vsys': - description: 'The vsys.' - default: 'vsys1' - validation: - not_values: - 'shared': 'The vsys cannot be "shared". Use the "shared" path instead.' - 'from_panorama_shared': - description: 'Located in shared in the config pushed from Panorama.' + path: ["config", "shared"] + - name: "vsys" + description: "Located in a specific vsys." + devices: + - panorama + - ngfw + xpath: + path: + - "config" + - "devices" + - "$ngfw_device" + - "vsys" + - "$vsys" + vars: + - name: "ngfw_device" + description: "The NGFW device." + default: "localhost.localdomain" + - name: "vsys" + description: "The vsys." + default: "vsys1" + validators: + - type: not-values + spec: + values: + - value: "shared" + error: 'The vsys cannot be "shared". Use the "shared" path instead.' + - name: "from_panorama_shared" + description: "Located in shared in the config pushed from Panorama." read_only: true - device: - ngfw: true + devices: + - ngfw xpath: - - 'config' - - 'panorama' - - 'shared' - 'from_panorama_vsys': - description: 'Located in a specific vsys in the config pushed from Panorama.' + path: + - "config" + - "panorama" + - "shared" + - name: "from_panorama_vsys" + description: "Located in a specific vsys in the config pushed from Panorama." read_only: true - device: - ngfw: true + devices: + - ngfw xpath: - - 'config' - - 'panorama' - - 'vsys' - - '{{ Entry $vsys }}' - vars: - 'vsys': - description: 'The vsys.' - default: 'vsys1' - validation: - not_values: - 'shared': 'The vsys cannot be "shared". Use the "shared" path instead.' - 'device_group': - description: 'Located in a specific device group.' - device: - panorama: true + path: + - "config" + - "panorama" + - "vsys" + - "$vsys" + vars: + - name: "vsys" + description: "The vsys." + default: "vsys1" + validators: + - type: not-values + spec: + values: + - value: "shared" + error: 'The vsys cannot be "shared". Use the "shared" path instead.' + - name: "device_group" + description: "Located in a specific device group." + devices: + - panorama xpath: - - 'config' - - 'devices' - - '{{ Entry $panorama_device }}' - - 'device-group' - - '{{ Entry $device_group }}' - vars: - 'panorama_device': - description: 'The panorama device.' - default: 'localhost.localdomain' - 'device_group': - description: 'The device group.' - required: true - validation: - not_values: - 'shared': 'The device group cannot be "shared". Use the "shared" path instead.' -entry: - name: - description: 'The name of the service group.' - length: - min: 1 - max: 63 -version: '10.1.0' + path: + - "config" + - "devices" + - "$panorama_device" + - "device-group" + - "$device_group" + vars: + - name: "panorama_device" + description: "The panorama device." + default: "localhost.localdomain" + - name: "device_group" + description: "The device group." + required: true + validators: + - type: not-values + spec: + values: + - value: "shared" + error: 'The device group cannot be "shared". Use the "shared" path instead.' +entries: + - name: name + description: "The name of the service." + validators: + - type: length + spec: + min: 1 + max: 63 +version: "10.1.0" spec: params: - description: - description: 'The description.' + - name: description + description: "The description." type: string - length: - min: 0 - max: 1023 + validators: + - type: length + spec: + min: 0 + max: 1023 profiles: - - - xpath: ["description"] - members: - description: 'Service group members.' + - xpath: ["description"] + - name: members + description: "Service group members." type: list - count: - max: 63 - items: - type: string + validators: + - type: count + spec: + max: 63 + spec: + items: + type: string profiles: - - xpath: [ "members" ] + - xpath: ["members"] type: member - tags: - description: 'The administrative tags.' + - name: tags + description: "The administrative tags." type: list - count: - max: 64 - items: - type: string - length: - max: 127 + validators: + - type: count + spec: + max: 64 + spec: + items: + type: string + validators: + - type: length + spec: + max: 127 profiles: - - - type: member + - type: member xpath: ["tag"] diff --git a/specs/objects/service.yaml b/specs/objects/service.yaml index ac23d1a5..72700fd7 100644 --- a/specs/objects/service.yaml +++ b/specs/objects/service.yaml @@ -1,206 +1,240 @@ -name: 'Service' +name: "Service" terraform_provider_config: - suffix: 'service_object' -go_sdk_path: - - 'objects' - - 'service' + suffix: "service_object" +go_sdk_config: + package: + - "objects" + - "service" xpath_suffix: - - 'service' + - "service" locations: - 'shared': - description: 'Located in shared.' - device: - panorama: true - ngfw: true - xpath: ['config', 'shared'] - 'vsys': - description: 'Located in a specific vsys.' - device: - panorama: true - ngfw: true + - name: "shared" + description: "Located in shared." + devices: + - panorama + - ngfw xpath: - - 'config' - - 'devices' - - '{{ Entry $ngfw_device }}' - - 'vsys' - - '{{ Entry $vsys }}' - vars: - 'ngfw_device': - description: 'The NGFW device.' - default: 'localhost.localdomain' - 'vsys': - description: 'The vsys.' - default: 'vsys1' - validation: - not_values: - 'shared': 'The vsys cannot be "shared". Use the "shared" path instead.' - 'from_panorama_shared': - description: 'Located in shared in the config pushed from Panorama.' + path: ["config", "shared"] + - name: "vsys" + description: "Located in a specific vsys." + devices: + - panorama + - ngfw + xpath: + path: + - "config" + - "devices" + - "$ngfw_device" + - "vsys" + - "$vsys" + vars: + - name: "ngfw_device" + description: "The NGFW device." + default: "localhost.localdomain" + - name: "vsys" + description: "The vsys." + default: "vsys1" + validators: + - type: not-values + spec: + values: + - value: "shared" + error: 'The vsys cannot be "shared". Use the "shared" path instead.' + - name: "from_panorama_shared" + description: "Located in shared in the config pushed from Panorama." read_only: true - device: - ngfw: true + devices: + - ngfw xpath: - - 'config' - - 'panorama' - - 'shared' - 'from_panorama_vsys': - description: 'Located in a specific vsys in the config pushed from Panorama.' + path: + - "config" + - "panorama" + - "shared" + - name: "from_panorama_vsys" + description: "Located in a specific vsys in the config pushed from Panorama." read_only: true - device: - ngfw: true + devices: + - ngfw xpath: - - 'config' - - 'panorama' - - 'vsys' - - '{{ Entry $vsys }}' - vars: - 'vsys': - description: 'The vsys.' - default: 'vsys1' - validation: - not_values: - 'shared': 'The vsys cannot be "shared". Use the "shared" path instead.' - 'device_group': - description: 'Located in a specific device group.' - device: - panorama: true + path: + - "config" + - "panorama" + - "vsys" + - "$vsys" + vars: + - name: "vsys" + description: "The vsys." + default: "vsys1" + validators: + - type: not-values + spec: + values: + - value: "shared" + error: 'The vsys cannot be "shared". Use the "shared" path instead.' + - name: "device_group" + description: "Located in a specific device group." + devices: + - panorama xpath: - - 'config' - - 'devices' - - '{{ Entry $panorama_device }}' - - 'device-group' - - '{{ Entry $device_group }}' - vars: - 'panorama_device': - description: 'The panorama device.' - default: 'localhost.localdomain' - 'device_group': - description: 'The device group.' - required: true - validation: - not_values: - 'shared': 'The device group cannot be "shared". Use the "shared" path instead.' -entry: - name: - description: 'The name of the service.' - length: - min: 1 - max: 63 -version: '10.1.0' + path: + - "config" + - "devices" + - "$panorama_device" + - "device-group" + - "$device_group" + vars: + - name: "panorama_device" + description: "The panorama device." + default: "localhost.localdomain" + - name: "device_group" + description: "The device group." + required: true + validators: + - type: not-values + spec: + values: + - value: "shared" + error: 'The device group cannot be "shared". Use the "shared" path instead.' +entries: + - name: name + description: "The name of the service." + validators: + - type: length + spec: + min: 1 + max: 63 +version: "10.1.0" spec: params: - description: - description: 'The description.' + - name: description + description: "The description." type: string - length: - min: 0 - max: 1023 + validators: + - type: length + spec: + min: 0 + max: 1023 profiles: - - - xpath: ["description"] - tags: - description: 'The administrative tags.' + - xpath: ["description"] + - name: tags + description: "The administrative tags." type: list - count: - max: 64 - items: - type: string - length: - max: 127 profiles: - - - type: member + - type: member xpath: ["tag"] - protocol: - description: 'The protocol (TCP or UDP).' + validators: + - type: count + spec: + max: 64 + spec: + items: + type: string + validators: + - type: length + spec: + max: 127 + - name: protocol + type: object + description: "The protocol (TCP or UDP)." profiles: - - - xpath: ["protocol"] + - xpath: ["protocol"] spec: - one_of: - tcp: - description: 'TCP protocol' + variants: + - name: tcp + type: object + description: "TCP protocol" profiles: - - - xpath: ["tcp"] + - xpath: ["tcp"] spec: params: - destination-port: - description: 'The destination port.' + - name: destination-port + description: "The destination port." type: int64 - value: - min: 0 - max: 1023 + validators: + - type: range + spec: + min: 0 + max: 1023 profiles: - - xpath: [ "port" ] - source-port: - description: 'The source port.' + - xpath: ["port"] + - name: source-port + description: "The source port." type: int64 - value: - min: 0 - max: 1023 + validators: + - type: range + spec: + min: 0 + max: 1023 profiles: - - xpath: [ "source-port" ] - override: - description: 'Override session timeout.' + - xpath: ["source-port"] + - name: override + type: object + description: "Override session timeout." profiles: - - xpath: [ "override", "yes" ] + - xpath: ["override", "yes"] spec: params: - 'timeout': - description: 'TCP session timeout value (in second)' + - name: "timeout" + description: "TCP session timeout value (in second)" type: int64 profiles: - - xpath: [ "timeout" ] - 'halfclose-timeout': - description: 'TCP session half-close timeout value (in second)' + - xpath: ["timeout"] + - name: "halfclose-timeout" + description: "TCP session half-close timeout value (in second)" type: int64 profiles: - - xpath: [ "halfclose-timeout" ] - 'timewait-timeout': - description: 'TCP session time-wait timeout value (in second)' + - xpath: ["halfclose-timeout"] + - name: "timewait-timeout" + description: "TCP session time-wait timeout value (in second)" type: int64 profiles: - - xpath: [ "timewait-timeout" ] - udp: - description: 'UDP protocol' + - xpath: ["timewait-timeout"] + - name: udp + type: object + description: "UDP protocol" profiles: - - - xpath: ["udp"] + - xpath: ["udp"] spec: params: - destination-port: - description: 'The destination port.' + - name: destination-port + description: "The destination port." type: int64 - value: - min: 0 - max: 1023 + validators: + - type: range + spec: + min: 0 + max: 1023 profiles: - - xpath: [ "port" ] - source-port: - description: 'The source port.' + - xpath: ["port"] + - name: source-port + description: "The source port." type: int64 - value: - min: 0 - max: 1023 + validators: + - type: range + spec: + min: 0 + max: 1023 profiles: - - xpath: [ "source-port" ] - override: - description: 'Override session timeout.' + - xpath: ["source-port"] + - name: override + type: object + description: "Override session timeout." profiles: - - xpath: [ "override" ] + - xpath: ["override"] spec: - one_of: - yes: + variants: + - name: yes + type: object profiles: - - - xpath: [ "yes"] + - xpath: ["yes"] spec: params: - 'timeout': - description: 'UDP session timeout value (in second)' + - name: "timeout" + type: int64 + description: "UDP session timeout value (in second)" profiles: - - xpath: [ "timeout" ] - no: + - xpath: ["timeout"] + - name: no + type: nil profiles: - - xpath: [ "no" ] + - xpath: ["no"] diff --git a/specs/objects/tag.yaml b/specs/objects/tag.yaml index 501f5751..e0097f42 100644 --- a/specs/objects/tag.yaml +++ b/specs/objects/tag.yaml @@ -1,191 +1,220 @@ -name: 'Tag' +name: "Tag" terraform_provider_config: - suffix: 'administrative_tag' -go_sdk_path: - - 'objects' - - 'tag' + suffix: "administrative_tag" +go_sdk_config: + package: + - "objects" + - "tag" xpath_suffix: - - 'tag' + - "tag" locations: - 'shared': - description: 'Located in shared.' - device: - panorama: true - ngfw: true - xpath: ['config', 'shared'] - 'vsys': - description: 'Located in a specific vsys.' - device: - panorama: true - ngfw: true + - name: "shared" + description: "Located in shared." + devices: + - panorama + - ngfw xpath: - - 'config' - - 'devices' - - '{{ Entry $ngfw_device }}' - - 'vsys' - - '{{ Entry $vsys }}' - vars: - 'ngfw_device': - description: 'The NGFW device.' - default: 'localhost.localdomain' - 'vsys': - description: 'The vsys.' - default: 'vsys1' - validation: - not_values: - 'shared': 'The vsys cannot be "shared". Use the "shared" path instead.' - 'from_panorama_shared': - description: 'Located in shared in the config pushed from Panorama.' + path: ["config", "shared"] + - name: "vsys" + description: "Located in a specific vsys." + devices: + - panorama + - ngfw + xpath: + path: + - "config" + - "devices" + - "$ngfw_device" + - "vsys" + - "$vsys" + vars: + - name: "ngfw_device" + description: "The NGFW device." + default: "localhost.localdomain" + - name: "vsys" + description: "The vsys." + default: "vsys1" + validators: + - type: not-values + spec: + values: + - value: "shared" + error: 'The vsys cannot be "shared". Use the "shared" path instead.' + - name: "from_panorama_shared" + description: "Located in shared in the config pushed from Panorama." read_only: true - device: - ngfw: true + devices: + - ngfw xpath: - - 'config' - - 'panorama' - - 'shared' - 'from_panorama_vsys': - description: 'Located in a specific vsys in the config pushed from Panorama.' + path: + - "config" + - "panorama" + - "shared" + - name: "from_panorama_vsys" + description: "Located in a specific vsys in the config pushed from Panorama." read_only: true - device: - ngfw: true + devices: + - ngfw xpath: - - 'config' - - 'panorama' - - 'vsys' - - '{{ Entry $vsys }}' - vars: - 'vsys': - description: 'The vsys.' - default: 'vsys1' - validation: - not_values: - 'shared': 'The vsys cannot be "shared". Use the "shared" path instead.' - 'device_group': - description: 'Located in a specific device group.' - device: - panorama: true + path: + - "config" + - "panorama" + - "vsys" + - "$vsys" + vars: + - name: "vsys" + description: "The vsys." + default: "vsys1" + validators: + - type: not-values + spec: + values: + - value: "shared" + error: 'The vsys cannot be "shared". Use the "shared" path instead.' + - name: "device_group" + description: "Located in a specific device group." + devices: + - panorama xpath: - - 'config' - - 'devices' - - '{{ Entry $panorama_device }}' - - 'device-group' - - '{{ Entry $device_group }}' - vars: - 'panorama_device': - description: 'The panorama device.' - default: 'localhost.localdomain' - 'device_group': - description: 'The device group.' - required: true - validation: - not_values: - 'shared': 'The device group cannot be "shared". Use the "shared" path instead.' -entry: - name: - description: 'The name of the tag.' - length: - min: 1 - max: 127 -version: '10.1.0' + path: + - "config" + - "devices" + - "$panorama_device" + - "device-group" + - "$device_group" + vars: + - name: "panorama_device" + description: "The panorama device." + default: "localhost.localdomain" + - name: "device_group" + description: "The device group." + required: true + validators: + - type: not-values + spec: + values: + - value: "shared" + error: 'The device group cannot be "shared". Use the "shared" path instead.' +entries: + - name: name + description: "The name of the tag." + validators: + - type: length + spec: + min: 1 + max: 127 +version: "10.1.0" spec: params: - color: - description: 'The color.' - type: string + - name: color + description: "The color." + type: enum + validators: + - type: values + spec: + values: ["color1", "color2", "color24"] + spec: + values: + - value: color1 + const: red + - value: color2 + const: green + - value: color24 + const: azure blue profiles: - - - xpath: ["color"] - comments: - description: 'Comments.' + - xpath: ["color"] + - name: comments + description: "Comments." type: string - length: - min: 0 - max: 1023 + validators: + - type: length + spec: + min: 0 + max: 1023 profiles: - - - xpath: ["comments"] -const: - color: - values: - red: - value: color1 - green: - value: color2 - blue: - value: color3 - yellow: - value: color4 - copper: - value: color5 - orange: - value: color6 - purple: - value: color7 - gray: - value: color8 - light green: - value: color9 - cyan: - value: color10 - light gray: - value: color11 - blue gray: - value: color12 - lime: - value: color13 - black: - value: color14 - gold: - value: color15 - brown: - value: color16 - olive: - value: color17 - maroon: - value: color19 - red-orange: - value: color20 - yellow-orange: - value: color21 - forest green: - value: color22 - turquoise blue: - value: color23 - azure blue: - value: color24 - cerulean blue: - value: color25 - midnight blue: - value: color26 - medium blue: - value: color27 - cobalt blue: - value: color28 - violet blue: - value: color29 - blue violet: - value: color30 - medium violet: - value: color31 - medium rose: - value: color32 - lavender: - value: color33 - orchid: - value: color34 - thistle: - value: color35 - peach: - value: color36 - salmon: - value: color37 - magenta: - value: color38 - red violet: - value: color39 - mahogany: - value: color40 - burnt sienna: - value: color41 - chestnut: - value: color42 + - xpath: ["comments"] +# const: +# color: +# values: +# red: +# color1 +# green: +# value: color2 +# blue: +# value: color3 +# yellow: +# value: color4 +# copper: +# value: color5 +# orange: +# value: color6 +# purple: +# value: color7 +# gray: +# value: color8 +# light green: +# value: color9 +# cyan: +# value: color10 +# light gray: +# value: color11 +# blue gray: +# value: color12 +# lime: +# value: color13 +# black: +# value: color14 +# gold: +# value: color15 +# brown: +# value: color16 +# olive: +# value: color17 +# maroon: +# value: color19 +# red-orange: +# value: color20 +# yellow-orange: +# value: color21 +# forest green: +# value: color22 +# turquoise blue: +# value: color23 +# azure blue: +# value: color24 +# cerulean blue: +# value: color25 +# midnight blue: +# value: color26 +# medium blue: +# value: color27 +# cobalt blue: +# value: color28 +# violet blue: +# value: color29 +# blue violet: +# value: color30 +# medium violet: +# value: color31 +# medium rose: +# value: color32 +# lavender: +# value: color33 +# orchid: +# value: color34 +# thistle: +# value: color35 +# peach: +# value: color36 +# salmon: +# value: color37 +# magenta: +# value: color38 +# red violet: +# value: color39 +# mahogany: +# value: color40 +# burnt sienna: +# value: color41 +# chestnut: +# value: color42 diff --git a/specs/panorama/device-group.yaml b/specs/panorama/device-group.yaml index 0ce1c7b7..a7f3c08e 100644 --- a/specs/panorama/device-group.yaml +++ b/specs/panorama/device-group.yaml @@ -1,61 +1,67 @@ -name: 'Device group' +name: "Device group" terraform_provider_config: - suffix: 'device_group' -go_sdk_path: - - 'panorama' - - 'device_group' + suffix: "device_group" +go_sdk_config: + package: + - "panorama" + - "device_group" xpath_suffix: - - 'device-group' + - "device-group" locations: - 'panorama': - description: 'Located in a specific Panorama.' - device: - panorama: true + - name: "panorama" + description: "Located in a specific Panorama." + devices: + - panorama xpath: - - 'config' - - 'devices' - - '{{ Entry $panorama_device }}' - vars: - 'panorama_device': - description: 'The Panorama device.' - default: 'localhost.localdomain' -entry: - name: - description: 'The name of the device group.' - length: - min: 1 - max: 31 -version: '10.1.0' + path: + - "config" + - "devices" + - "$panorama_device" + vars: + - name: "panorama_device" + description: "The Panorama device." + default: "localhost.localdomain" +entries: + - name: name + description: "The name of the service." + validators: + - type: length + spec: + min: 1 + max: 63 +version: "10.1.0" spec: params: - description: - description: 'The description.' + - name: description + description: "The description." type: string - length: - min: 0 - max: 255 + validators: + - type: length + spec: + min: 0 + max: 255 profiles: - - - xpath: ["description"] - templates: - description: 'List of reference templates' + - xpath: ["description"] + - name: templates + description: "List of reference templates" type: list - items: - type: string + spec: + items: + type: string profiles: - - - type: member + - type: member xpath: ["reference-templates"] - devices: - description: 'List of devices' + - name: devices + description: "List of devices" type: list - items: - type: string + spec: + items: + type: string profiles: - type: member xpath: ["devices"] - authorization_code: - description: 'Authorization code' + - name: authorization_code + type: string + description: "Authorization code" profiles: - - - xpath: ["authorization-code"] + - xpath: ["authorization-code"] diff --git a/specs/panorama/template-stack.yaml b/specs/panorama/template-stack.yaml index f72c9f77..0c0b4504 100644 --- a/specs/panorama/template-stack.yaml +++ b/specs/panorama/template-stack.yaml @@ -1,72 +1,77 @@ -name: 'Template stack' +name: "Template stack" terraform_provider_config: - suffix: 'template_stack' -go_sdk_path: - - 'panorama' - - 'template_stack' + suffix: "template_stack" +go_sdk_config: + package: + - "panorama" + - "template_stack" xpath_suffix: - - 'template-stack' + - "template-stack" locations: - 'panorama': - description: 'Located in a specific Panorama.' - device: - panorama: true + - name: "panorama" + description: "Located in a specific Panorama." + devices: + - panorama xpath: - - 'config' - - 'devices' - - '{{ Entry $panorama_device }}' - vars: - 'panorama_device': - description: 'The Panorama device.' - default: 'localhost.localdomain' -entry: - name: - description: 'The name of the template stack.' - length: - min: 1 - max: 63 -version: '10.1.0' + path: + - "config" + - "devices" + - "$panorama_device" + vars: + - name: "panorama_device" + description: "The Panorama device." + default: "localhost.localdomain" +entries: + - name: name + description: "The name of the service." + validators: + - type: length + spec: + min: 1 + max: 63 +version: "10.1.0" spec: params: - description: - description: 'The description.' + - name: description + description: "The description." type: string - length: - min: 0 - max: 255 + validators: + - type: length + spec: + min: 0 + max: 255 profiles: - - - xpath: ["description"] - templates: - description: 'List of templates' + - xpath: ["description"] + - name: templates + description: "List of templates" type: list - items: - type: string + spec: + items: + type: string profiles: - - - type: member + - type: member xpath: ["templates"] - devices: - description: 'List of devices' + - name: devices + description: "List of devices" type: list - items: - type: string + spec: + items: + type: string profiles: - - - type: entry + - type: entry xpath: ["devices"] - default-vsys: - description: 'Default virtual system' + - name: default-vsys + description: "Default virtual system" type: string profiles: - - - xpath: ["settings", "default-vsys"] - user-group-source: + - xpath: ["settings", "default-vsys"] + - name: user-group-source + type: object profiles: - xpath: ["user-group-source"] spec: params: - master-device: + - name: master-device type: string profiles: - xpath: ["master-device"] diff --git a/specs/panorama/template.yaml b/specs/panorama/template.yaml index e642dc71..a71fdb52 100644 --- a/specs/panorama/template.yaml +++ b/specs/panorama/template.yaml @@ -1,91 +1,95 @@ -name: 'Template' +name: "Template" terraform_provider_config: - suffix: 'template' -go_sdk_path: - - 'panorama' - - 'template' + suffix: "template" +go_sdk_config: + package: + - "panorama" + - "template" xpath_suffix: - - 'template' + - "template" locations: - 'panorama': - description: 'Located in a specific Panorama.' - device: - panorama: true + - name: "panorama" + description: "Located in a specific Panorama." + devices: + - panorama xpath: - - 'config' - - 'devices' - - '{{ Entry $panorama_device }}' - vars: - 'panorama_device': - description: 'The Panorama device.' - default: 'localhost.localdomain' -entry: - name: - description: 'The name of the template.' - length: - min: 1 - max: 63 -version: '10.1.0' + path: + - "config" + - "devices" + - "$panorama_device" + vars: + - name: "panorama_device" + description: "The Panorama device." + default: "localhost.localdomain" +entries: + - name: name + description: "The name of the service." + validators: + - type: length + spec: + min: 1 + max: 63 +version: "10.1.0" spec: params: - description: - description: 'The description.' + - name: description + description: "The description." type: string - length: - min: 0 - max: 255 + validators: + - type: length + spec: + min: 0 + max: 255 profiles: - - - xpath: ["description"] - default-vsys: - description: 'Default virtual system' + - xpath: ["description"] + - name: default-vsys + description: "Default virtual system" type: string profiles: - - - xpath: ["settings", "default-vsys"] - config: + - xpath: ["settings", "default-vsys"] + - name: config + type: object profiles: - - - xpath: ["config"] + - xpath: ["config"] spec: params: - devices: + - name: devices type: list - items: - type: entry profiles: - - - xpath: ["devices", "entry"] + - xpath: ["devices", "entry"] type: entry spec: - params: - vsys: - type: list - items: - type: entry - profiles: - - - xpath: ["vsys", "entry"] - type: entry - spec: - params: - import: - profiles: - - - xpath: ["import"] - spec: - params: - network: - profiles: - - - xpath: ["network"] - spec: - params: - interfaces: - type: list - items: - type: string - profiles: - - - xpath: ["interface"] - type: member + items: + type: object + spec: + params: + - name: vsys + type: list + profiles: + - xpath: ["vsys", "entry"] + type: entry + spec: + items: + type: object + spec: + params: + - name: import + type: object + profiles: + - xpath: ["import"] + spec: + params: + - name: network + type: object + profiles: + - xpath: ["network"] + spec: + params: + - name: interfaces + type: list + profiles: + - xpath: ["interface"] + type: member + spec: + items: + type: string diff --git a/specs/policies/security-policy-rule.yaml b/specs/policies/security-policy-rule.yaml index 2a04b4dc..40047e63 100644 --- a/specs/policies/security-policy-rule.yaml +++ b/specs/policies/security-policy-rule.yaml @@ -1,399 +1,509 @@ -name: 'Security policy rule' +name: "Security policy rule" terraform_provider_config: - suffix: 'security_policy_rule' -go_sdk_path: - - 'policies' - - 'rules' - - 'security' + suffix: "security_policy_rule" +go_sdk_config: + package: + - "policies" + - "rules" + - "security" xpath_suffix: - - 'security' - - 'rules' + - "security" + - "rules" locations: - 'shared': - description: 'Located in shared.' - device: - panorama: true - ngfw: true + - name: "shared" + description: "Located in shared." + devices: + - panorama + - ngfw xpath: - - 'config' - - 'shared' - - '{{ Object $rulebase }}' - vars: - 'rulebase': - description: 'The rulebase.' - default: 'pre-rulebase' - validation: - values: ['post-rulebase', 'pre-rulebase'] - 'vsys': - description: 'Located in a specific vsys.' - device: - panorama: true - ngfw: true + path: + - "config" + - "shared" + - "$rulebase" + vars: + - name: "rulebase" + type: object + description: "The rulebase." + default: "pre-rulebase" + validators: + - type: values + spec: + values: ["post-rulebase", "pre-rulebase"] + - name: "vsys" + description: "Located in a specific vsys." + devices: + - panorama + - ngfw xpath: - - 'config' - - 'devices' - - '{{ Entry $ngfw_device }}' - - 'vsys' - - '{{ Entry $vsys }}' - - 'rulebase' - vars: - 'ngfw_device': - description: 'The NGFW device.' - default: 'localhost.localdomain' - 'vsys': - description: 'The vsys.' - default: 'vsys1' - validation: - not_values: - 'shared': 'The vsys cannot be "shared". Use the "shared" path instead.' - 'rulebase': - description: 'The rulebase.' - default: 'pre-rulebase' - validation: - values: ['post-rulebase', 'pre-rulebase'] - 'from_panorama_vsys': - description: 'Located in a specific vsys in the config pushed from Panorama.' + path: + - "config" + - "devices" + - "$ngfw_device" + - "vsys" + - "$vsys" + - "rulebase" + vars: + - name: "ngfw_device" + description: "The NGFW device." + default: "localhost.localdomain" + - name: "vsys" + description: "The vsys." + default: "vsys1" + validators: + - type: not-values + spec: + values: + - value: "shared" + error: 'The vsys cannot be "shared". Use the "shared" path instead.' + - name: "rulebase" + description: "The rulebase." + default: "pre-rulebase" + validators: + - type: values + spec: + values: ["post-rulebase", "pre-rulebase"] + - name: "from_panorama_vsys" + description: "Located in a specific vsys in the config pushed from Panorama." read_only: true - device: - ngfw: true + devices: + - ngfw xpath: - - 'config' - - 'panorama' - - 'vsys' - - '{{ Entry $vsys }}' - - 'rulebase' - vars: - 'vsys': - description: 'The vsys.' - default: 'vsys1' - validation: - not_values: - 'shared': 'The vsys cannot be "shared". Use the "shared" path instead.' - 'device_group': - description: 'Located in a specific device group.' - device: - panorama: true + path: + - "config" + - "panorama" + - "vsys" + - "$vsys" + - "rulebase" + vars: + - name: "vsys" + description: "The vsys." + default: "vsys1" + validators: + - type: not-values + spec: + values: + - value: "shared" + error: 'The vsys cannot be "shared". Use the "shared" path instead.' + - name: "device_group" + description: "Located in a specific device group." + devices: + - panorama xpath: - - 'config' - - 'devices' - - '{{ Entry $panorama_device }}' - - 'device-group' - - '{{ Entry $device_group }}' - - '{{ Object $rulebase }}' - vars: - 'panorama_device': - description: 'The panorama device.' - default: 'localhost.localdomain' - 'device_group': - description: 'The device group.' - required: true - validation: - not_values: - 'shared': 'The device group cannot be "shared". Use the "shared" path instead.' - 'rulebase': - description: 'The rulebase.' - default: 'pre-rulebase' - validation: - values: ['post-rulebase', 'pre-rulebase'] -entry: - name: - description: 'The name of the security policy rule.' - length: - min: 1 - max: 63 - validation: - not_values: - 'intrazone-default': 'The intrazone-default is a reserved name.' - 'interzone-default': 'The interzone-default is a reserved name.' -version: '10.1.0' + path: + - "config" + - "devices" + - "$panorama_device" + - "device-group" + - "$device_group" + - "$rulebase" + vars: + - name: "panorama_device" + description: "The panorama device." + default: "localhost.localdomain" + - name: "device_group" + description: "The device group." + required: true + validators: + - type: not-values + spec: + values: + - value: "shared" + error: 'The device group cannot be "shared". Use the "shared" path instead.' + - name: "rulebase" + type: object + description: "The rulebase." + default: "pre-rulebase" + validators: + - type: values + spec: + values: ["post-rulebase", "pre-rulebase"] +entries: + - name: name + description: "The name of the security policy rule." + validators: + - type: length + spec: + min: 1 + max: 63 + - type: not-values + spec: + values: + - value: "intrazone-default" + error: "The intrazone-default is a reserved name." + - value: "interzone-default" + error: "The interzone-default is a reserved name." +version: "10.1.0" spec: params: - description: - description: 'The description.' + - name: description + description: "The description." type: string - length: - min: 0 - max: 1023 + validators: + - type: length + spec: + min: 0 + max: 1023 profiles: - - - xpath: ["description"] - uuid: - description: 'The UUID value.' - regex: '[0-9A-Fa-f]{8}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{12}' - length: - min: 3 - max: 36 + - xpath: ["description"] + - name: uuid + type: string + description: "The UUID value." + codegen_overrides: + terraform: + computed: true + validators: + - type: regexp + spec: + expr: "[0-9A-Fa-f]{8}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{12}" + - type: length + spec: + min: 3 + max: 36 profiles: - - xpath: [ "uuid" ] - tags: - description: 'The administrative tags.' + - xpath: ["uuid"] + - name: tags + description: "The administrative tags." type: list - count: - max: 64 - items: - type: string - length: - max: 127 + validators: + - type: count + spec: + max: 64 + spec: + items: + type: string + validators: + - type: length + spec: + max: 127 profiles: - - - type: member + - type: member xpath: ["tag"] - source_zones: - description: 'Source zones' + - name: source_zones + description: "Source zones" type: list - count: - max: 31 - items: - type: string + validators: + - type: count + spec: + max: 31 + spec: + items: + type: string profiles: - - - type: member + - type: member xpath: ["from"] - destination_zones: - description: 'Destination zones' + - name: destination_zones + description: "Destination zones" type: list - count: - max: 31 - items: - type: string + validators: + - type: count + spec: + max: 31 + spec: + items: + type: string profiles: - - - type: member + - type: member xpath: ["to"] - source_addresses: - description: 'Source addresses' + - name: source_addresses + description: "Source addresses" type: list - count: - max: 63 - items: - type: string + validators: + - type: count + spec: + max: 63 + spec: + items: + type: string profiles: - - - type: member + - type: member xpath: ["source"] - destination_addresses: - description: 'Destination addresses' + - name: destination_addresses + description: "Destination addresses" type: list - count: - max: 63 - items: - type: string + validators: + - type: count + spec: + max: 63 + spec: + items: + type: string profiles: - - - type: member + - type: member xpath: ["destination"] - source_users: - description: 'Source users' + - name: source_users + description: "Source users" type: list - count: - max: 1023 - items: - type: string + validators: + - type: count + spec: + max: 1023 + spec: + items: + type: string profiles: - - - type: member + - type: member xpath: ["source-user"] - services: - description: 'Services' + - name: services + description: "Services" type: list - count: - max: 63 - items: - type: string + validators: + - type: count + spec: + max: 1023 + spec: + items: + type: string profiles: - - - type: member + - type: member xpath: ["service"] - categories: - description: 'Categories' + - name: categories + description: "Categories" type: list - count: - max: 63 - items: - type: string + validators: + - type: count + spec: + max: 63 + spec: + items: + type: string profiles: - - - type: member + - type: member xpath: ["category"] - applications: - description: 'Applications' + - name: applications + description: "Applications" type: list - count: - max: 63 - items: - type: string + validators: + - type: count + spec: + max: 63 + spec: + items: + type: string profiles: - - - type: member + - type: member xpath: ["application"] - source_hips: - description: 'Source HIPs' + - name: source_hips + description: "Source HIPs" type: list - count: - max: 63 - items: - type: string + validators: + - type: count + spec: + max: 63 + spec: + items: + type: string profiles: - - - type: member + - type: member xpath: ["source-hip"] - destination_hips: - description: 'Destination HIPs' + - name: destination_hips + description: "Destination HIPs" type: list - count: - max: 63 - items: - type: string + validators: + - type: count + spec: + max: 63 + spec: + items: + type: string profiles: - - - type: member + - type: member xpath: ["destination-hip"] - negate_source: - description: 'Negate source address' + - name: negate_source + description: "Negate source address" type: bool profiles: - - - xpath: ["negate-source"] - negate_destination: - description: 'Negate destination address' + - xpath: ["negate-source"] + - name: negate_destination + description: "Negate destination address" type: bool profiles: - - - xpath: ["negate-destination"] - disabled: - description: 'Disable the rule' + - xpath: ["negate-destination"] + - name: disabled + description: "Disable the rule" type: bool profiles: - - - xpath: ["disabled"] - action: - description: 'Action' - type: string - default: 'allow' - values: ['deny', 'allow', 'drop', 'reset-client', 'reset-server', 'reset-both'] + - xpath: ["disabled"] + - name: action + description: "Action" + type: enum + validators: + - type: values + spec: + values: + [ + "deny", + "allow", + "drop", + "reset-client", + "reset-server", + "reset-both", + ] + spec: + default: "allow" + values: + [ + { value: deny }, + { value: allow }, + { value: drop }, + { value: reset-client }, + { value: reset-server }, + { value: "reset-both" }, + ] profiles: - - - xpath: ["action"] - rule_type: - description: 'Rule type' - type: string - default: 'allow' - values: ['universal', 'intrazone', 'interzone'] + - xpath: ["action"] + - name: rule_type + description: "Rule type" + type: enum + validators: + - type: values + spec: + values: ["universal", "intrazone", "interzone"] + spec: + default: "intrazone" + values: + [ + { value: "universal" }, + { value: "intrazone" }, + { value: "interzone" }, + ] profiles: - - - xpath: ["rule-type"] - log_setting: - description: 'Log forwarding' + - xpath: ["rule-type"] + - name: log_setting + description: "Log forwarding" type: string - length: - min: 0 - max: 63 + validators: + - type: length + spec: + min: 0 + max: 63 profiles: - - - xpath: ["log-setting"] - log_start: - description: 'Log at session start' + - xpath: ["log-setting"] + - name: log_start + description: "Log at session start" type: bool profiles: - - - xpath: ["log-start"] - log_end: - description: 'Log at session end' + - xpath: ["log-start"] + - name: log_end + description: "Log at session end" type: bool - default: true + spec: + default: true profiles: - - - xpath: ["log-end"] - icmp_unreachable: - description: 'Send ICMP unreachable' + - xpath: ["log-end"] + - name: icmp_unreachable + description: "Send ICMP unreachable" type: bool profiles: - xpath: ["icmp-unreachable"] - disable_server_response_inspection: - description: 'Disable Server Response Inspection' + - name: disable_server_response_inspection + description: "Disable Server Response Inspection" type: bool profiles: - - xpath: [ "option", "disable-server-response-inspection" ] - profile_setting: + - xpath: ["option", "disable-server-response-inspection"] + - name: profile_setting + type: object profiles: - - xpath: [ "profile-setting" ] + - xpath: ["profile-setting"] spec: - one_of: - group: + variants: + - name: group + type: nil profiles: - - xpath: [ "group" ] - profiles: + - xpath: ["group"] + - name: profiles + type: object profiles: - - xpath: [ "profiles" ] + - xpath: ["profiles"] spec: params: - virus: - description: 'Antivirus profile' + - name: virus + description: "Antivirus profile" type: list - count: - max: 1 - items: - type: string + validators: + - type: count + spec: + max: 1 + spec: + items: + type: string profiles: - type: member - xpath: [ "virus" ] - spyware: - description: 'Anti-Spyware profile' + xpath: ["virus"] + - name: spyware + description: "Anti-Spyware profile" type: list - count: - max: 1 - items: - type: string + validators: + - type: count + spec: + max: 1 + spec: + items: + type: string profiles: - type: member - xpath: [ "spyware" ] - vulnerability: - description: 'Vulnerability Protection profile' + xpath: ["spyware"] + - name: vulnerability + description: "Vulnerability Protection profile" type: list - count: - max: 1 - items: - type: string + validators: + - type: count + spec: + max: 1 + spec: + items: + type: string profiles: - type: member - xpath: [ "vulnerability" ] - url_filtering: - description: 'URL filtering profile' + xpath: ["vulnerability"] + - name: url_filtering + description: "URL filtering profile" type: list - count: - max: 1 - items: - type: string + validators: + - type: count + spec: + max: 1 + spec: + items: + type: string profiles: - type: member - xpath: [ "url-filtering" ] - file_blocking: - description: 'File blocking profile' + xpath: ["url-filtering"] + - name: file_blocking + description: "File blocking profile" type: list - count: - max: 1 - items: - type: string + validators: + - type: count + spec: + max: 1 + spec: + items: + type: string profiles: - type: member - xpath: [ "file-blocking" ] - wildfire_analysis: - description: 'WildFire analysis profile' + xpath: ["file-blocking"] + - name: wildfire_analysis + description: "WildFire analysis profile" type: list - count: - max: 1 - items: - type: string + validators: + - type: count + spec: + max: 1 + spec: + items: + type: string profiles: - type: member - xpath: [ "wildfire-analysis" ] - data_filtering: - description: 'Data filtering profile' + xpath: ["wildfire-analysis"] + - name: data_filtering + description: "Data filtering profile" type: list - count: - max: 1 - items: - type: string + validators: + - type: count + spec: + max: 1 + spec: + items: + type: string profiles: - type: member - xpath: [ "data-filtering" ] + xpath: ["data-filtering"] diff --git a/specs/schema/import.schema.json b/specs/schema/import.schema.json new file mode 100644 index 00000000..fedbb4be --- /dev/null +++ b/specs/schema/import.schema.json @@ -0,0 +1,15 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "import.schema.json", + "type": "object", + "additionalProperties": false, + "required": ["name", "xpath"], + "properties": { + "name": { "type": "string" }, + "xpath": { "$ref": "xpath.schema.json" }, + "only_for_params": { + "type": "array", + "items": { "type": "string" } + } + } +} diff --git a/specs/schema/location.schema.json b/specs/schema/location.schema.json new file mode 100644 index 00000000..733e9222 --- /dev/null +++ b/specs/schema/location.schema.json @@ -0,0 +1,29 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "location.schema.json", + "title": "Codegen location schema", + "description": "Location schema describes PAN-OS location parameters", + "required": ["name", "description", "devices", "xpath"], + "properties": { + "name": { + "type": "string" + }, + "description": { + "type": "string" + }, + "read_only": { + "type": "boolean" + }, + "devices": { + "type": "array", + "items": { + "type": "string", + "oneOf": [{ "enum": ["panorama", "ngfw"] }] + } + }, + "xpath": { + "$ref": "xpath.schema.json" + } + }, + "additionalProperties": false +} diff --git a/specs/schema/object.schema.json b/specs/schema/object.schema.json new file mode 100644 index 00000000..c455bf99 --- /dev/null +++ b/specs/schema/object.schema.json @@ -0,0 +1,80 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "id": "https://paloaltonetworks/codegen/object.schema.json", + "title": "Codegen object", + "description": "Top-level object describing XML API for Panorama and PAN-OS devices", + "type": "object", + "additionalProperties": false, + "required": [ + "name", + "terraform_provider_config", + "go_sdk_config", + "locations", + "version", + "spec" + ], + "properties": { + "name": { "type": "string" }, + "terraform_provider_config": { + "type": "object", + "required": ["suffix"], + "properties": { + "suffix": { + "type": "string" + } + } + }, + "go_sdk_config": { + "type": "object", + "required": ["package"], + "properties": { + "package": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "xpath_suffix": { + "type": "array", + "items": { + "type": "string" + } + }, + "locations": { + "type": "array", + "items": { + "$ref": "location.schema.json" + } + }, + "entries": { + "type": "array", + "items": { + "$ref": "#/$defs/entry" + } + }, + "imports": { + "type": "array", + "items": { "$ref": "import.schema.json" } + }, + "version": { "type": "string" }, + "spec": { "$ref": "spec.schema.json" } + }, + "$defs": { + "entry": { + "type": "object", + "required": ["name", "description"], + "properties": { + "name": { "type": "string" }, + "description": { "type": "string" }, + "validators": { + "type": "array", + "items": { + "$ref": "validator.schema.json" + } + } + } + } + } +} diff --git a/specs/schema/profile.schema.json b/specs/schema/profile.schema.json new file mode 100644 index 00000000..9ef27b2b --- /dev/null +++ b/specs/schema/profile.schema.json @@ -0,0 +1,13 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "profile.schema.json", + "type": "object", + "required": ["xpath"], + "additionalProperties": false, + "properties": { + "type": { "type": "string" }, + "xpath": { "type": "array", "items": { "type": "string" } }, + "min_version": { "type": "string" }, + "max_version": { "type": "string" } + } +} diff --git a/specs/schema/schema.json b/specs/schema/schema.json new file mode 100644 index 00000000..c9f101ae --- /dev/null +++ b/specs/schema/schema.json @@ -0,0 +1,31 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "id": "https://paloaltonetworks/codegen/object.schema.json", + "title": "Codegen object", + "description": "Top-level object describing XML API for Panorama and PAN-OS devices", + "type": "object", + "required": [ + "name", + "terraform_provider_config", + "go_sdk_config", + "xpath_suffix", + "locations", + "entries", + "version", + "spec" + ], + "properties": { + "name": { + "type": "string" + }, + "terraform_provider_config": { + "type": "object", + "required": ["suffix"], + "properties": { + "suffix": { + "type": "string" + } + } + } + } +} diff --git a/specs/schema/spec.schema.json b/specs/schema/spec.schema.json new file mode 100644 index 00000000..f5956f18 --- /dev/null +++ b/specs/schema/spec.schema.json @@ -0,0 +1,121 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "type": "object", + "additionalProperties": false, + "properties": { + "params": { + "type": "array", + "items": { "$ref": "#/$defs/item" } + }, + "variants": { + "type": "array", + "items": { "$ref": "#/$defs/item" } + } + }, + "$defs": { + "item": { + "type": "object", + "additionalProperties": false, + "required": ["name", "type"], + "properties": { + "name": { "type": "string" }, + "description": { "type": "string" }, + "codegen_overrides": { + "type": "object", + "additionalProperties": false, + "properties": { + "terraform": { + "type": "object", + "additionalProperties": false, + "properties": { + "codegen": { "type": "boolean" }, + "sensitive": { "type": "boolean" } + } + } + } + }, + "hashing": { + "type": "object", + "additionalProperties": false, + "properties": { + "type": { "type": "string" } + } + }, + "type": { "$ref": "#/$defs/type" }, + "profiles": { + "type": "array", + "items": { "$ref": "profile.schema.json" } + }, + "validators": { + "type": "array", + "items": { "$ref": "validator.schema.json" } + }, + "spec": { + "oneOf": [ + { "$ref": "#/$defs/simple" }, + { "$ref": "#/$defs/enum" }, + { "$ref": "#/$defs/list" }, + { "$ref": "#" } + ] + } + } + }, + "simple": { + "type": "object", + "additionalProperties": false, + "properties": { + "default": true, + "validators": { + "type": "array", + "items": { "$ref": "validator.schema.json" } + }, + "required": { "type": "boolean" } + } + }, + "enum": { + "type": "object", + "additionalProperties": false, + "required": ["values"], + "properties": { + "default": true, + "values": { + "type": "array", + "items": { + "type": "object", + "additionalProperties": false, + "required": ["value"], + "properties": { + "value": { "type": "string" }, + "const": { "type": "string" } + } + } + } + } + }, + "list": { + "type": "object", + "additionalProperties": false, + "required": ["items"], + "properties": { + "items": { + "type": "object", + "additionalProperties": false, + "properties": { + "type": { "$ref": "#/$defs/type" }, + "spec": { "$ref": "#" }, + "validators": { + "type": "array", + "items": { "$ref": "validator.schema.json" } + } + } + } + } + }, + "type": { + "type": "string", + "oneOf": [ + { "enum": ["string", "bool", "int64", "object", "list", "enum", "nil"] } + ] + } + } +} diff --git a/specs/schema/validator.schema.json b/specs/schema/validator.schema.json new file mode 100644 index 00000000..41ab0e61 --- /dev/null +++ b/specs/schema/validator.schema.json @@ -0,0 +1,65 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "validator.schema.json", + "type": "object", + "properties": { + "type": { "type": "string" }, + "spec": { + "type": "object", + "oneOf": [ + { "$ref": "#/$defs/validators/not-values" }, + { "$ref": "#/$defs/validators/values" }, + { "$ref": "#/$defs/validators/length" }, + { "$ref": "#/$defs/validators/regexp" } + ] + } + }, + "$defs": { + "validators": { + "not-values": { + "type": "object", + "required": ["values"], + "properties": { + "values": { + "type": "array", + "items": { + "type": "object", + "required": ["value", "error"], + "properties": { + "value": { "type": "string" }, + "error": { "type": "string" } + } + } + } + } + }, + "values": { + "type": "object", + "required": ["values"], + "properties": { + "values": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "length": { + "type": "object", + "additionalProperties": false, + "properties": { + "min": { "type": "number" }, + "max": { "type": "number" } + } + }, + "regexp": { + "type": "object", + "additionalProperties": false, + "properties": { + "expr": { "type": "string" } + } + } + } + } +} diff --git a/specs/schema/xpath.schema.json b/specs/schema/xpath.schema.json new file mode 100644 index 00000000..8b54ffe3 --- /dev/null +++ b/specs/schema/xpath.schema.json @@ -0,0 +1,41 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "xpath.schema.json", + "title": "Codegen Xpath schema", + "description": "Xpath schema describes Xpath used to define path of a given object", + "type": "object", + "required": ["path"], + "additionalProperties": false, + "properties": { + "path": { + "type": "array", + "items": { + "type": "string" + } + }, + "vars": { + "type": "array", + "items": { + "$ref": "#/$defs/xpath-variable" + } + } + }, + "$defs": { + "xpath-variable": { + "type": "object", + "required": ["name", "description"], + "properties": { + "name": { "type": "string" }, + "description": { "type": "string" }, + "default": { "type": "string" }, + "required": { "type": "boolean" }, + "validators": { + "type": "array", + "items": { + "$ref": "validator.schema.json" + } + } + } + } + } +}