From 4016ae96309c736b6e7b114ecff79c2de31e1ba7 Mon Sep 17 00:00:00 2001 From: Krzysztof Klimonda Date: Tue, 14 Jan 2025 12:01:54 +0100 Subject: [PATCH] feat(specs): Initial panos_ethernet_layer3_subinterface spec --- assets/terraform/internal/manager/config.go | 28 +- assets/terraform/internal/manager/entry.go | 39 +- .../internal/manager/entry_import.go | 54 +- pkg/generate/generator.go | 1 + pkg/properties/normalized.go | 219 +- pkg/schema/object/object.go | 24 +- pkg/schema/parameter/parameter.go | 9 + pkg/translate/assignments.go | 4 +- pkg/translate/structs.go | 8 + pkg/translate/terraform_provider/funcs.go | 162 +- pkg/translate/terraform_provider/template.go | 66 +- .../terraform_provider_file.go | 42 +- .../network/subinterface/ethernet/layer3.yaml | 2594 +++++++++++++++++ templates/sdk/entry.tmpl | 29 +- templates/sdk/location.tmpl | 15 + templates/sdk/service.tmpl | 277 +- 16 files changed, 3291 insertions(+), 280 deletions(-) create mode 100644 specs/network/subinterface/ethernet/layer3.yaml diff --git a/assets/terraform/internal/manager/config.go b/assets/terraform/internal/manager/config.go index be7c003d..26fdb5db 100644 --- a/assets/terraform/internal/manager/config.go +++ b/assets/terraform/internal/manager/config.go @@ -18,13 +18,14 @@ type TFConfigObject[E any] interface { type SDKConfigService[C any, L ConfigLocation] interface { Create(context.Context, L, C) (C, error) + CreateWithXpath(context.Context, string, C) error Update(context.Context, L, C) (C, error) - Read(context.Context, L, string) (C, error) + ReadWithXpath(context.Context, string, string) (C, error) Delete(context.Context, L, C) error } type ConfigLocation interface { - Xpath(version.Number) ([]string, error) + XpathWithComponents(version.Number, ...string) ([]string, error) } type ConfigObjectManager[C any, L ConfigLocation, S SDKConfigService[C, L]] struct { @@ -41,16 +42,31 @@ func NewConfigObjectManager[C any, L ConfigLocation, S SDKConfigService[C, L]](c } } -func (o *ConfigObjectManager[C, L, S]) Create(ctx context.Context, location L, config C) (C, error) { - return o.service.Create(ctx, location, config) +func (o *ConfigObjectManager[C, L, S]) Create(ctx context.Context, location L, components []string, config C) (C, error) { + xpath, err := location.XpathWithComponents(o.client.Versioning(), components...) + if err != nil { + return *new(C), err + } + + err = o.service.CreateWithXpath(ctx, util.AsXpath(xpath), config) + if err != nil { + return *new(C), err + } + + return o.Read(ctx, location, components) } func (o *ConfigObjectManager[C, L, S]) Update(ctx context.Context, location L, config C) (C, error) { return o.service.Update(ctx, location, config) } -func (o *ConfigObjectManager[C, L, S]) Read(ctx context.Context, location L) (C, error) { - obj, err := o.service.Read(ctx, location, "get") +func (o *ConfigObjectManager[C, L, S]) Read(ctx context.Context, location L, components []string) (C, error) { + xpath, err := location.XpathWithComponents(o.client.Versioning(), components...) + if err != nil { + return *new(C), err + } + + obj, err := o.service.ReadWithXpath(ctx, util.AsXpath(xpath), "get") if err != nil && sdkerrors.IsObjectNotFound(err) { return obj, ErrObjectNotFound } diff --git a/assets/terraform/internal/manager/entry.go b/assets/terraform/internal/manager/entry.go index cf2135fc..a4c12e76 100644 --- a/assets/terraform/internal/manager/entry.go +++ b/assets/terraform/internal/manager/entry.go @@ -2,6 +2,7 @@ package manager import ( "context" + "errors" "fmt" "log/slog" @@ -33,13 +34,15 @@ type EntryObject interface { } type EntryLocation interface { + XpathWithComponents(version.Number, ...string) ([]string, error) XpathWithEntryName(version.Number, string) ([]string, error) } type SDKEntryService[E EntryObject, L EntryLocation] interface { + CreateWithXpath(context.Context, string, E) error + ReadWithXpath(context.Context, string, string) (E, error) Create(context.Context, L, E) (E, error) List(context.Context, L, string, string, string) ([]E, error) - Read(context.Context, L, string, string) (E, error) Update(context.Context, L, E, string) (E, error) Delete(context.Context, L, ...string) error } @@ -82,8 +85,13 @@ func (o *EntryObjectManager[E, L, S]) ReadMany(ctx context.Context, location L, return filtered, nil } -func (o *EntryObjectManager[E, L, S]) Read(ctx context.Context, location L, name string) (E, error) { - object, err := o.service.Read(ctx, location, name, "get") +func (o *EntryObjectManager[E, L, S]) Read(ctx context.Context, location L, components []string) (E, error) { + xpath, err := location.XpathWithComponents(o.client.Versioning(), components...) + if err != nil { + return *new(E), err + } + + object, err := o.service.ReadWithXpath(ctx, util.AsXpath(xpath), "get") if err != nil { if sdkerrors.IsObjectNotFound(err) { return *new(E), ErrObjectNotFound @@ -94,20 +102,27 @@ func (o *EntryObjectManager[E, L, S]) Read(ctx context.Context, location L, name return object, nil } -func (o *EntryObjectManager[E, T, S]) Create(ctx context.Context, location T, entry E) (E, error) { - existing, err := o.service.List(ctx, location, "get", "", "") - if err != nil && !sdkerrors.IsObjectNotFound(err) { +func (o *EntryObjectManager[E, L, S]) Create(ctx context.Context, location L, components []string, entry E) (E, error) { + _, err := o.Read(ctx, location, components) + if err == nil { + return *new(E), &Error{err: ErrConflict, message: fmt.Sprintf("entry '%s' already exists", entry.EntryName())} + } + + if err != nil && !errors.Is(err, ErrObjectNotFound) { return *new(E), err } - for _, elt := range existing { - if elt.EntryName() == entry.EntryName() { - return *new(E), ErrConflict - } + xpath, err := location.XpathWithComponents(o.client.Versioning(), components...) + if err != nil { + return *new(E), err + } + + err = o.service.CreateWithXpath(ctx, util.AsXpath(xpath[:len(xpath)-1]), entry) + if err != nil { + return *new(E), err } - obj, err := o.service.Create(ctx, location, entry) - return obj, err + return o.Read(ctx, location, components) } func (o *EntryObjectManager[E, L, S]) CreateMany(ctx context.Context, location L, entries []E) ([]E, error) { diff --git a/assets/terraform/internal/manager/entry_import.go b/assets/terraform/internal/manager/entry_import.go index e98a23fe..e8e93a59 100644 --- a/assets/terraform/internal/manager/entry_import.go +++ b/assets/terraform/internal/manager/entry_import.go @@ -2,16 +2,23 @@ package manager import ( "context" + "errors" + "fmt" sdkerrors "github.com/PaloAltoNetworks/pango/errors" + "github.com/PaloAltoNetworks/pango/util" ) type SDKImportableEntryService[E EntryObject, L EntryLocation, IL ImportLocation] interface { Create(context.Context, L, []IL, E) (E, error) + CreateWithXpath(context.Context, string, E) error Read(context.Context, L, string, string) (E, error) + ReadWithXpath(context.Context, string, string) (E, error) List(context.Context, L, string, string, string) ([]E, error) Update(context.Context, L, E, string) (E, error) Delete(context.Context, L, []IL, ...string) error + ImportToLocations(context.Context, L, []IL, string) error + UnimportFromLocations(context.Context, L, []IL, []string) error } type ImportableEntryObjectManager[E EntryObject, L EntryLocation, IL ImportLocation, IS SDKImportableEntryService[E, L, IL]] struct { @@ -34,29 +41,44 @@ func (o *ImportableEntryObjectManager[E, L, IL, IS]) ReadMany(ctx context.Contex return nil, &Error{err: ErrInternal, message: "called ReadMany on an importable singular resource"} } -func (o *ImportableEntryObjectManager[E, L, IL, IS]) Read(ctx context.Context, location L, name string) (E, error) { - object, err := o.service.Read(ctx, location, name, "get") +func (o *ImportableEntryObjectManager[E, L, IL, IS]) Read(ctx context.Context, location L, components []string) (E, error) { + xpath, err := location.XpathWithComponents(o.client.Versioning(), components...) if err != nil { - return *new(E), ErrObjectNotFound + return *new(E), err + } + + object, err := o.service.ReadWithXpath(ctx, util.AsXpath(xpath), "get") + if err != nil { + if sdkerrors.IsObjectNotFound(err) { + return *new(E), ErrObjectNotFound + } + return *new(E), &Error{err: err} } return object, nil } -func (o *ImportableEntryObjectManager[E, L, IL, IS]) Create(ctx context.Context, location L, importLocs []IL, entry E) (E, error) { - existing, err := o.service.List(ctx, location, "get", "", "") - if err != nil && !sdkerrors.IsObjectNotFound(err) { +func (o *ImportableEntryObjectManager[E, L, IL, IS]) Create(ctx context.Context, location L, components []string, entry E) (E, error) { + _, err := o.Read(ctx, location, components) + if err == nil { + return *new(E), &Error{err: ErrConflict, message: fmt.Sprintf("entry '%s' already exists", entry.EntryName())} + } + + if err != nil && !errors.Is(err, ErrObjectNotFound) { return *new(E), err } - for _, elt := range existing { - if elt.EntryName() == entry.EntryName() { - return *new(E), ErrConflict - } + xpath, err := location.XpathWithComponents(o.client.Versioning(), components...) + if err != nil { + return *new(E), err + } + + err = o.service.CreateWithXpath(ctx, util.AsXpath(xpath[:len(xpath)-1]), entry) + if err != nil { + return *new(E), err } - obj, err := o.service.Create(ctx, location, importLocs, entry) - return obj, err + return o.Read(ctx, location, components) } func (o *ImportableEntryObjectManager[E, L, IL, IS]) Update(ctx context.Context, location L, entry E, name string) (E, error) { @@ -75,3 +97,11 @@ func (o *ImportableEntryObjectManager[E, L, IL, IS]) Delete(ctx context.Context, } return nil } + +func (o *ImportableEntryObjectManager[E, L, IL, IS]) ImportToLocations(ctx context.Context, location L, importLocs []IL, entry string) error { + return o.service.ImportToLocations(ctx, location, importLocs, entry) +} + +func (o *ImportableEntryObjectManager[E, L, IL, IS]) UnimportFromLocations(ctx context.Context, location L, importLocs []IL, entry string) error { + return o.service.UnimportFromLocations(ctx, location, importLocs, []string{entry}) +} diff --git a/pkg/generate/generator.go b/pkg/generate/generator.go index ae0cf689..df6cc072 100644 --- a/pkg/generate/generator.go +++ b/pkg/generate/generator.go @@ -274,6 +274,7 @@ func (c *Creator) parseTemplate(templateName string) (*template.Template, error) "generateEntryXpath": translate.GenerateEntryXpath, "nestedSpecs": translate.NestedSpecs, "createGoSuffixFromVersion": translate.CreateGoSuffixFromVersionTmpl, + "paramNotSkipped": translate.ParamNotSkippedTmpl, "paramSupportedInVersion": translate.ParamSupportedInVersionTmpl, "xmlPathSuffixes": translate.XmlPathSuffixes, "underscore": naming.Underscore, diff --git a/pkg/properties/normalized.go b/pkg/properties/normalized.go index bcc7020c..35506d3a 100644 --- a/pkg/properties/normalized.go +++ b/pkg/properties/normalized.go @@ -1,6 +1,7 @@ package properties import ( + "bytes" "fmt" "io/fs" "maps" @@ -9,6 +10,7 @@ import ( "slices" "strconv" "strings" + "text/template" "github.com/paloaltonetworks/pan-os-codegen/pkg/content" "github.com/paloaltonetworks/pan-os-codegen/pkg/naming" @@ -24,7 +26,7 @@ type Normalization struct { TerraformProviderConfig TerraformProviderConfig `json:"terraform_provider_config" yaml:"terraform_provider_config"` GoSdkSkip bool `json:"go_sdk_skip" yaml:"go_sdk_skip"` GoSdkPath []string `json:"go_sdk_path" yaml:"go_sdk_path"` - XpathSuffix []string `json:"xpath_suffix" yaml:"xpath_suffix"` + PanosXpath PanosXpath `json:"panos_xpath" yaml:"panos_xpath"` Locations map[string]*Location `json:"locations" yaml:"locations"` Entry *Entry `json:"entry" yaml:"entry"` Imports []Import `json:"imports" yaml:"imports"` @@ -33,6 +35,11 @@ type Normalization struct { Const map[string]*Const `json:"const" yaml:"const"` } +type PanosXpath struct { + Path []string `yaml:"path"` + Variables []object.PanosXpathVariable `yaml:"vars"` +} + type Import struct { Variant *NameVariant Type *NameVariant @@ -83,6 +90,7 @@ type TerraformProviderConfig struct { } type NameVariant struct { + Original string Underscore string CamelCase string LowerCamelCase string @@ -90,6 +98,7 @@ type NameVariant struct { func NewNameVariant(name string) *NameVariant { return &NameVariant{ + Original: name, Underscore: naming.Underscore("", name, ""), CamelCase: naming.CamelCase("", name, "", true), LowerCamelCase: naming.CamelCase("", name, "", false), @@ -163,6 +172,7 @@ type SpecParam struct { Name *NameVariant Description string `json:"description" yaml:"description"` TerraformProviderConfig *SpecParamTerraformProviderConfig `json:"terraform_provider_config" yaml:"terraform_provider_config"` + GoSdkConfig *SpecParamGoSdkConfig `json:"gosdk_config" yaml:"gosdk_config"` IsNil bool `json:"-" yaml:"-"` Type string `json:"type" yaml:"type"` Default string `json:"default" yaml:"default"` @@ -177,6 +187,10 @@ type SpecParam struct { Spec *Spec `json:"spec" yaml:"spec"` } +type SpecParamGoSdkConfig struct { + Skip *bool `json:"skip" yaml:"skip"` +} + type SpecParamTerraformProviderConfig struct { Name *string `json:"name" yaml:"name"` Type *string `json:"type" yaml:"type"` @@ -372,6 +386,14 @@ func (o *SpecParam) HasPrivateParameters() bool { return false } +func (o *SpecParam) IsTerraformOnly() bool { + if o.GoSdkConfig != nil && o.GoSdkConfig.Skip != nil { + return *o.GoSdkConfig.Skip + } + + return false +} + func (o *SpecParam) IsPrivateParameter() bool { if o.TerraformProviderConfig != nil && o.TerraformProviderConfig.Private != nil { return *o.TerraformProviderConfig.Private @@ -514,6 +536,7 @@ func schemaParameterToSpecParameter(schemaSpec *parameter.Parameter) (*SpecParam } var terraformProviderConfig *SpecParamTerraformProviderConfig + var goSdkConfig *SpecParamGoSdkConfig if schemaSpec.CodegenOverrides != nil { var variantCheck *string if schemaSpec.CodegenOverrides.Terraform.VariantCheck != nil { @@ -530,6 +553,10 @@ func schemaParameterToSpecParameter(schemaSpec *parameter.Parameter) (*SpecParam Required: schemaSpec.CodegenOverrides.Terraform.Required, VariantCheck: variantCheck, } + + goSdkConfig = &SpecParamGoSdkConfig{ + Skip: schemaSpec.CodegenOverrides.GoSdk.Skip, + } } specParameter := &SpecParam{ Description: schemaSpec.Description, @@ -537,6 +564,7 @@ func schemaParameterToSpecParameter(schemaSpec *parameter.Parameter) (*SpecParam IsNil: paramTypeIsNil, Default: defaultVal, Required: schemaSpec.Required, + GoSdkConfig: goSdkConfig, TerraformProviderConfig: terraformProviderConfig, Hashing: specHashing, Profiles: profiles, @@ -607,6 +635,12 @@ func schemaToSpec(object object.Object) (*Normalization, error) { for _, elt := range object.TerraformConfig.ResourceVariants { resourceVariants = append(resourceVariants, TerraformResourceVariant(elt)) } + + panosXpath := PanosXpath{ + Path: object.PanosXpath.Path, + Variables: object.PanosXpath.Variables, + } + spec := &Normalization{ Name: object.DisplayName, TerraformProviderConfig: TerraformProviderConfig{ @@ -622,11 +656,11 @@ func schemaToSpec(object object.Object) (*Normalization, error) { PluralName: object.TerraformConfig.PluralName, PluralDescription: object.TerraformConfig.PluralDescription, }, - Locations: make(map[string]*Location), - GoSdkSkip: object.GoSdkConfig.Skip, - GoSdkPath: object.GoSdkConfig.Package, - XpathSuffix: object.XpathSuffix, - Version: object.Version, + Locations: make(map[string]*Location), + GoSdkSkip: object.GoSdkConfig.Skip, + GoSdkPath: object.GoSdkConfig.Package, + PanosXpath: panosXpath, + Version: object.Version, Spec: &Spec{ Params: make(map[string]*SpecParam), OneOf: make(map[string]*SpecParam), @@ -714,11 +748,7 @@ func schemaToSpec(object object.Object) (*Normalization, error) { for _, xpathVariable := range location.Xpath.Variables { schemaXpathVars[xpathVariable.Name] = xpathVariable xpathVars[xpathVariable.Name] = ImportXpathVariable{ - Name: &NameVariant{ - Underscore: naming.Underscore("", xpathVariable.Name, ""), - CamelCase: naming.CamelCase("", xpathVariable.Name, "", true), - LowerCamelCase: naming.CamelCase("", xpathVariable.Name, "", false), - }, + Name: NewNameVariant(xpathVariable.Name), Description: xpathVariable.Description, Default: xpathVariable.Default, } @@ -728,11 +758,7 @@ func schemaToSpec(object object.Object) (*Normalization, error) { xpath = append(xpath, location.Xpath.Elements...) locations[location.Name] = ImportLocation{ - Name: &NameVariant{ - Underscore: naming.Underscore("", location.Name, ""), - CamelCase: naming.CamelCase("", location.Name, "", true), - LowerCamelCase: naming.CamelCase("", location.Name, "", false), - }, + Name: NewNameVariant(location.Name), Required: location.Required, XpathVariables: xpathVars, XpathElements: xpath, @@ -740,16 +766,8 @@ func schemaToSpec(object object.Object) (*Normalization, error) { } imports = append(imports, Import{ - Type: &NameVariant{ - Underscore: naming.Underscore("", elt.Type, ""), - CamelCase: naming.CamelCase("", elt.Type, "", true), - LowerCamelCase: naming.CamelCase("", elt.Type, "", false), - }, - Variant: &NameVariant{ - Underscore: naming.Underscore("", elt.Variant, ""), - CamelCase: naming.CamelCase("", elt.Variant, "", true), - LowerCamelCase: naming.CamelCase("", elt.Variant, "", false), - }, + Type: NewNameVariant(elt.Type), + Variant: NewNameVariant(elt.Variant), Locations: locations, }) } @@ -848,18 +866,10 @@ func ParseSpec(input []byte) (*Normalization, error) { // AddNameVariantsForLocation add name variants for location (under_score and CamelCase). func (spec *Normalization) AddNameVariantsForLocation() error { for key, location := range spec.Locations { - location.Name = &NameVariant{ - Underscore: naming.Underscore("", key, ""), - CamelCase: naming.CamelCase("", key, "", true), - LowerCamelCase: naming.CamelCase("", key, "", false), - } + location.Name = NewNameVariant(key) for subkey, variable := range location.Vars { - variable.Name = &NameVariant{ - Underscore: naming.Underscore("", subkey, ""), - CamelCase: naming.CamelCase("", subkey, "", true), - LowerCamelCase: naming.CamelCase("", subkey, "", false), - } + variable.Name = NewNameVariant(subkey) } } @@ -868,11 +878,7 @@ func (spec *Normalization) AddNameVariantsForLocation() error { // AddNameVariantsForParams recursively add name variants for params for nested specs. func AddNameVariantsForParams(name string, param *SpecParam) error { - param.Name = &NameVariant{ - Underscore: naming.Underscore("", name, ""), - CamelCase: naming.CamelCase("", name, "", true), - LowerCamelCase: naming.CamelCase("", name, "", false), - } + param.Name = NewNameVariant(name) if param.Spec != nil { for key, childParam := range param.Spec.Params { if err := AddNameVariantsForParams(key, childParam); err != nil { @@ -909,17 +915,9 @@ func (spec *Normalization) AddNameVariantsForParams() error { func (spec *Normalization) AddNameVariantsForTypes() error { if spec.Const != nil { for nameType, customType := range spec.Const { - customType.Name = &NameVariant{ - Underscore: naming.Underscore("", nameType, ""), - CamelCase: naming.CamelCase("", nameType, "", true), - LowerCamelCase: naming.CamelCase("", nameType, "", false), - } + customType.Name = NewNameVariant(nameType) for nameValue, customValue := range customType.Values { - customValue.Name = &NameVariant{ - Underscore: naming.Underscore("", nameValue, ""), - CamelCase: naming.CamelCase("", nameValue, "", true), - LowerCamelCase: naming.CamelCase("", nameValue, "", false), - } + customValue.Name = NewNameVariant(nameValue) } } } @@ -976,6 +974,123 @@ func (spec *Normalization) Sanity() error { return nil } +func (spec *Normalization) XpathSuffix() []string { + return spec.PanosXpath.Path +} + +func (spec *Normalization) ResourceXpathVariablesCount() int { + if spec.HasEntryName() && len(spec.PanosXpath.Variables) == 0 { + return 1 + } + + return len(spec.PanosXpath.Variables) +} + +const componentVariantTmpl = ` +{ + +var component string +{{- range .Variants }} +if component != "" { + return "", fmt.Errorf("invalid resource, multiple variants set") +} +if o.{{ .CamelCase }} != nil { + component = {{ .Original }} +} +{{- end }} +if component == "" { + return "", fmt.Errorf("invalid resource, missing xpath variant") +} + +} +` + +func (spec *Normalization) AttributesFromXpathComponents() map[string]int { + result := make(map[string]int) + for idx, elt := range spec.PanosXpath.Variables { + // "Entry Name" has special case handling all over the place + if elt.Name == "name" { + continue + } + if elt.Spec.Type != object.PanosXpathVariableValue { + continue + } + + variants := NewNameVariant(elt.Name) + result[variants.CamelCase] = idx + } + + return result +} + +func (spec *Normalization) ResourceXpathComponents() (string, error) { + var components []string + + tmpl := template.Must(template.New("component-variant").Parse(componentVariantTmpl)) + explicitNameVariable := false + for _, elt := range spec.PanosXpath.Variables { + if elt.Name == "name" { + explicitNameVariable = true + } + + var component string + name := NewNameVariant(elt.Name) + switch elt.Spec.Type { + case object.PanosXpathVariableValue: + component = fmt.Sprintf("components = append(components, o.%s)", name.CamelCase) + case object.PanosXpathVariableVariant: + var buf bytes.Buffer + err := tmpl.Execute(&buf, nil) + if err != nil { + return "", err + } + component = buf.String() + } + components = append(components, component) + } + + if !explicitNameVariable { + components = append(components, "components = append(components, o.Name)") + } + + return strings.Join(components, "\n"), nil +} + +func (spec *Normalization) ResourceXpathAssigments() (string, error) { + var elements []string + + variables := map[string]string{"$name": "name"} + for _, elt := range spec.PanosXpath.Variables { + variables[fmt.Sprintf("$%s", elt.Name)] = elt.Name + } + + explicitNameVariable := false + componentIdx := 0 + for _, elt := range spec.PanosXpath.Path { + if elt == "$name" { + explicitNameVariable = true + } + + _, found := variables[elt] + var assignment string + if found { + assignment = fmt.Sprintf("components[%d]", componentIdx) + componentIdx += 1 + } else { + assignment = fmt.Sprintf("\"%s\"", elt) + } + + elements = append(elements, assignment) + } + + if !explicitNameVariable { + elements = append(elements, fmt.Sprintf("components[%d]", componentIdx)) + } + + result := strings.Join(elements, ",") + return result, nil +} + // Validate validations for specification (normalization) e.g. check if XPath contain /. func (spec *Normalization) Validate() []error { var checks []error @@ -983,7 +1098,7 @@ func (spec *Normalization) Validate() []error { if strings.Contains(spec.TerraformProviderConfig.Suffix, "panos_") { checks = append(checks, fmt.Errorf("suffix for Terraform provider cannot contain `panos_`")) } - for _, suffix := range spec.XpathSuffix { + for _, suffix := range spec.XpathSuffix() { if strings.Contains(suffix, "/") { checks = append(checks, fmt.Errorf("XPath cannot contain /")) } diff --git a/pkg/schema/object/object.go b/pkg/schema/object/object.go index f7f3a6a6..3b52d01c 100644 --- a/pkg/schema/object/object.go +++ b/pkg/schema/object/object.go @@ -56,10 +56,32 @@ type Spec struct { Variants []*parameter.Parameter `yaml:"variants"` } +type PanosXpathVariableType string + +const ( + PanosXpathVariableValue PanosXpathVariableType = "value" + PanosXpathVariableVariant PanosXpathVariableType = "variant" +) + +type PanosXpathVariableSpec struct { + Type PanosXpathVariableType `yaml:"type"` + Xpath string `yaml:"xpath"` +} + +type PanosXpathVariable struct { + Name string `yaml:"name"` + Spec PanosXpathVariableSpec `yaml:"spec"` +} + +type PanosXpath struct { + Path []string `yaml:"path"` + Variables []PanosXpathVariable `yaml:"vars"` +} + type Object struct { Name string `yaml:"-"` DisplayName string `yaml:"name"` - XpathSuffix []string `yaml:"xpath_suffix"` + PanosXpath PanosXpath `yaml:"panos_xpath"` TerraformConfig *TerraformConfig `yaml:"terraform_provider_config"` Version string `yaml:"version"` GoSdkConfig *GoSdkConfig `yaml:"go_sdk_config"` diff --git a/pkg/schema/parameter/parameter.go b/pkg/schema/parameter/parameter.go index 54336cbb..ea5b934c 100644 --- a/pkg/schema/parameter/parameter.go +++ b/pkg/schema/parameter/parameter.go @@ -3,6 +3,7 @@ package parameter import ( "fmt" "log/slog" + "strings" "gopkg.in/yaml.v3" @@ -49,6 +50,10 @@ const ( VariantCheckExactlyOneOf VariantCheckType = "ExactlyOneOf" ) +type CodegenOverridesGoSdk struct { + Skip *bool `yaml:"skip"` +} + type CodegenOverridesTerraform struct { Name *string `yaml:"name"` Type *string `yaml:"type"` @@ -60,6 +65,7 @@ type CodegenOverridesTerraform struct { } type CodegenOverrides struct { + GoSdk CodegenOverridesGoSdk `yaml:"gosdk"` Terraform CodegenOverridesTerraform `yaml:"terraform"` } @@ -148,6 +154,9 @@ func (p *Parameter) UnmarshalYAML(n *yaml.Node) error { return errors.NewSchemaError(fmt.Sprintf("unsupported parameter type: '%s'", p.Type)) } + // Escape value of a description, making sure all backslashes are handled properly + obj.Description = strings.ReplaceAll(obj.Description, "\\", "\\\\") + // Finally, decode obj.Spec (which is yaml.Node type) into the parameter // spec structure return obj.Spec.Decode(p.Spec) diff --git a/pkg/translate/assignments.go b/pkg/translate/assignments.go index f4adb3c7..fd2ca8b7 100644 --- a/pkg/translate/assignments.go +++ b/pkg/translate/assignments.go @@ -94,7 +94,9 @@ func isParamListAndProfileTypeIsExtendedEntry(param *properties.SpecParam) bool } func appendSimpleAssignment(param *properties.SpecParam, objectType string, builder *strings.Builder) { - builder.WriteString(fmt.Sprintf("%s.%s = o.%s", objectType, param.Name.CamelCase, param.Name.CamelCase)) + if ParamNotSkippedTmpl(param) { + builder.WriteString(fmt.Sprintf("%s.%s = o.%s", objectType, param.Name.CamelCase, param.Name.CamelCase)) + } } func appendFunctionAssignment(param *properties.SpecParam, objectType string, functionName, additionalArguments string, builder *strings.Builder) { diff --git a/pkg/translate/structs.go b/pkg/translate/structs.go index c88a2b36..8c6273f2 100644 --- a/pkg/translate/structs.go +++ b/pkg/translate/structs.go @@ -460,6 +460,14 @@ func CreateGoSuffixFromVersion(v *version.Version) string { return fmt.Sprintf("_%s", strings.ReplaceAll(v.String(), ".", "_")) } +func ParamNotSkippedTmpl(param *properties.SpecParam) bool { + if param.GoSdkConfig != nil && param.GoSdkConfig.Skip != nil { + return !*param.GoSdkConfig.Skip + } + + return true +} + func ParamSupportedInVersionTmpl(param *properties.SpecParam, deviceVersion any) (bool, error) { if deviceVersion == nil { return true, nil diff --git a/pkg/translate/terraform_provider/funcs.go b/pkg/translate/terraform_provider/funcs.go index 0fb4335b..607bd5e3 100644 --- a/pkg/translate/terraform_provider/funcs.go +++ b/pkg/translate/terraform_provider/funcs.go @@ -12,6 +12,7 @@ import ( "github.com/paloaltonetworks/pan-os-codegen/pkg/imports" "github.com/paloaltonetworks/pan-os-codegen/pkg/naming" "github.com/paloaltonetworks/pan-os-codegen/pkg/properties" + "github.com/paloaltonetworks/pan-os-codegen/pkg/schema/object" ) type Entry struct { @@ -54,9 +55,14 @@ type spec struct { func renderSpecsForParams(params map[string]*properties.SpecParam, parentNames []string) []parameterSpec { var specs []parameterSpec for _, elt := range params { + if elt.IsTerraformOnly() { + continue + } + if elt.IsPrivateParameter() { continue } + var encryptionSpec *parameterEncryptionSpec if elt.Hashing != nil { path := strings.Join(append(parentNames, elt.Name.Underscore), " | ") @@ -611,6 +617,85 @@ func RenderCopyFromPangoFunctions(resourceTyp properties.ResourceType, pkgName s return processTemplate(copyFromPangoTmpl, "copy-from-pango", data, funcMap) } +const xpathComponentsGetterTmpl = ` +func (o *{{ .StructName }}Model) resourceXpathComponents() ([]string, error) { + var components []string +{{- range .Components }} + {{- if eq .Type "value" }} + components = append(components, pangoutil.AsEntryXpath( + []string{o.{{ .Name.CamelCase }}.ValueString()}, + )) + {{- else if eq .Type "variant" }} + { + var component string + {{- range .Variants }} + if component != "" { + return nil, fmt.Errorf("invalid resource xpath, multiple variants set") + } + if o.{{ .CamelCase }} != nil { + component = "{{ .Original }}" + } + {{- end }} + if component == "" { + return nil, fmt.Errorf("invalid resource xpath, must set one of variants") + } + components = append(components, component) + } + {{- end }} +{{- end }} + return components, nil +} +` + +func RenderXpathComponentsGetter(structName string, property *properties.Normalization) (string, error) { + type componentSpec struct { + Type string + Name *properties.NameVariant + Variants []*properties.NameVariant + } + + explicitNameComponent := false + var components []componentSpec + for _, elt := range property.PanosXpath.Variables { + if elt.Name == "name" { + explicitNameComponent = true + } + switch elt.Spec.Type { + case object.PanosXpathVariableValue: + components = append(components, componentSpec{ + Type: "value", + Name: properties.NewNameVariant(elt.Name), + }) + case object.PanosXpathVariableVariant: + var variants []*properties.NameVariant + for _, elt := range property.Spec.OneOf { + variants = append(variants, elt.Name) + } + components = append(components, componentSpec{ + Type: "variant", + Variants: variants, + }) + } + } + + if !explicitNameComponent && property.Entry != nil { + components = append(components, componentSpec{ + Type: "value", + Name: properties.NewNameVariant("name"), + }) + } + + data := struct { + StructName string + Components []componentSpec + }{ + StructName: structName, + Components: components, + } + + return processTemplate(xpathComponentsGetterTmpl, "xpath-components", data, commonFuncMap) +} + const renderLocationTmpl = ` {{- range .Locations }} type {{ .StructName }} struct { @@ -2549,18 +2634,19 @@ func ResourceCreateFunction(resourceTyp properties.ResourceType, names *NameProv resourceIsMap = true } data := map[string]interface{}{ - "HasEncryptedResources": paramSpec.HasEncryptedResources(), - "HasImports": len(paramSpec.Imports) > 0, - "Exhaustive": exhaustive, - "ResourceIsMap": resourceIsMap, - "ListAttribute": listAttributeVariant, - "EntryOrConfig": paramSpec.EntryOrConfig(), - "HasEntryName": paramSpec.HasEntryName(), - "structName": names.ResourceStructName, - "serviceName": naming.CamelCase("", serviceName, "", false), - "paramSpec": paramSpec.Spec, - "resourceSDKName": resourceSDKName, - "locations": paramSpec.Locations, + "HasEncryptedResources": paramSpec.HasEncryptedResources(), + "AttributesFromXpathComponents": paramSpec.AttributesFromXpathComponents(), + "HasImports": len(paramSpec.Imports) > 0, + "Exhaustive": exhaustive, + "ResourceIsMap": resourceIsMap, + "ListAttribute": listAttributeVariant, + "EntryOrConfig": paramSpec.EntryOrConfig(), + "HasEntryName": paramSpec.HasEntryName(), + "structName": names.ResourceStructName, + "serviceName": naming.CamelCase("", serviceName, "", false), + "paramSpec": paramSpec.Spec, + "resourceSDKName": resourceSDKName, + "locations": paramSpec.Locations, } return processTemplate(tmpl, "resource-create-function", data, funcMap) @@ -2601,18 +2687,19 @@ func DataSourceReadFunction(resourceTyp properties.ResourceType, names *NameProv resourceIsMap = true } data := map[string]interface{}{ - "ResourceOrDS": "DataSource", - "ResourceIsMap": resourceIsMap, - "HasEncryptedResources": paramSpec.HasEncryptedResources(), - "ListAttribute": listAttributeVariant, - "EntryOrConfig": paramSpec.EntryOrConfig(), - "HasEntryName": paramSpec.HasEntryName(), - "structName": names.StructName, - "resourceStructName": names.ResourceStructName, - "dataSourceStructName": names.DataSourceStructName, - "serviceName": naming.CamelCase("", serviceName, "", false), - "resourceSDKName": resourceSDKName, - "locations": paramSpec.Locations, + "ResourceOrDS": "DataSource", + "ResourceIsMap": resourceIsMap, + "HasEncryptedResources": paramSpec.HasEncryptedResources(), + "ListAttribute": listAttributeVariant, + "EntryOrConfig": paramSpec.EntryOrConfig(), + "ResourceXpathComponents": func() (string, error) { return paramSpec.ResourceXpathComponents() }, + "HasEntryName": paramSpec.HasEntryName(), + "structName": names.StructName, + "resourceStructName": names.ResourceStructName, + "dataSourceStructName": names.DataSourceStructName, + "serviceName": naming.CamelCase("", serviceName, "", false), + "resourceSDKName": resourceSDKName, + "locations": paramSpec.Locations, } funcMap := template.FuncMap{ @@ -2667,19 +2754,20 @@ func ResourceReadFunction(resourceTyp properties.ResourceType, names *NameProvid resourceIsMap = true } data := map[string]interface{}{ - "ResourceOrDS": "Resource", - "ResourceIsMap": resourceIsMap, - "HasEncryptedResources": paramSpec.HasEncryptedResources(), - "ListAttribute": listAttributeVariant, - "Exhaustive": exhaustive, - "EntryOrConfig": paramSpec.EntryOrConfig(), - "HasEntryName": paramSpec.HasEntryName(), - "structName": names.StructName, - "datasourceStructName": names.DataSourceStructName, - "resourceStructName": names.ResourceStructName, - "serviceName": naming.CamelCase("", serviceName, "", false), - "resourceSDKName": resourceSDKName, - "locations": paramSpec.Locations, + "ResourceOrDS": "Resource", + "ResourceIsMap": resourceIsMap, + "HasEncryptedResources": paramSpec.HasEncryptedResources(), + "AttributesFromXpathComponents": paramSpec.AttributesFromXpathComponents(), + "ListAttribute": listAttributeVariant, + "Exhaustive": exhaustive, + "EntryOrConfig": paramSpec.EntryOrConfig(), + "HasEntryName": paramSpec.HasEntryName(), + "structName": names.StructName, + "datasourceStructName": names.DataSourceStructName, + "resourceStructName": names.ResourceStructName, + "serviceName": naming.CamelCase("", serviceName, "", false), + "resourceSDKName": resourceSDKName, + "locations": paramSpec.Locations, } funcMap := template.FuncMap{ diff --git a/pkg/translate/terraform_provider/template.go b/pkg/translate/terraform_provider/template.go index 13c5b580..17b81f61 100644 --- a/pkg/translate/terraform_provider/template.go +++ b/pkg/translate/terraform_provider/template.go @@ -339,6 +339,10 @@ func (r *{{ resourceStructName }}) Configure(ctx context.Context, req resource.C {{ RenderCopyFromPangoFunctions }} +{{- if not IsResourcePlural }} +{{ RenderXpathComponentsGetter }} +{{- end }} + func (r *{{ resourceStructName }}) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { {{ ResourceCreateFunction resourceStructName serviceName}} } @@ -612,17 +616,35 @@ const resourceCreateFunction = ` */ // Perform the operation. + + components, err := state.resourceXpathComponents() + if err != nil { + resp.Diagnostics.AddError("Error creating resource xpath", err.Error()) + return + } + {{- if .HasImports }} var importLocation {{ .resourceSDKName }}.ImportLocation {{ RenderImportLocationAssignment "state.Location" "importLocation" }} - created, err := r.manager.Create(ctx, location, []{{ .resourceSDKName }}.ImportLocation{importLocation}, obj) + created, err := r.manager.Create(ctx, location, components, obj) + if err != nil { + resp.Diagnostics.AddError("Error in create", err.Error()) + return + } + + err = r.manager.ImportToLocations(ctx, location, []{{ .resourceSDKName }}.ImportLocation{importLocation}, obj.Name) + if err != nil { + resp.Diagnostics.AddError("Failed to import resource into location", err.Error()) + return + } {{- else }} - created, err := r.manager.Create(ctx, location, obj) -{{- end }} + created, err := r.manager.Create(ctx, location, components, obj) if err != nil { resp.Diagnostics.AddError("Error in create", err.Error()) return } +{{- end }} + resp.Diagnostics.Append(state.CopyFromPango(ctx, created, {{ $ev }})...) if resp.Diagnostics.HasError() { @@ -866,12 +888,13 @@ const resourceReadFunction = ` }) - // Perform the operation. -{{- if .HasEntryName }} - object, err := o.manager.Read(ctx, location, savestate.Name.ValueString()) -{{- else }} - object, err := o.manager.Read(ctx, location) -{{- end }} + components, err := savestate.resourceXpathComponents() + if err != nil { + resp.Diagnostics.AddError("Error creating resource xpath", err.Error()) + return + } + + object, err := o.manager.Read(ctx, location, components) if err != nil { if errors.Is(err, sdkmanager.ErrObjectNotFound) { {{- if eq .ResourceOrDS "DataSource" }} @@ -902,6 +925,15 @@ const resourceReadFunction = ` resp.Diagnostics.Append(ev_diags...) {{- end }} +{{- range $name, $index := .AttributesFromXpathComponents }} + { + value := components[{{ $index }}] + // component elements are entry-formatted for xpath rendering, + // each one looking like this: entry[@name='VALUE'], so we have + // to somehow slice the actual value from the component. + state.{{ $name }} = types.StringValue(value[13:len(value)-2]) + } +{{- end }} // Done. resp.Diagnostics.Append(resp.State.Set(ctx, &state)...) @@ -1126,11 +1158,13 @@ const resourceUpdateFunction = ` return } -{{- if .HasEntryName }} - obj, err := r.manager.Read(ctx, location, plan.Name.ValueString()) -{{- else }} - obj, err := r.manager.Read(ctx, location) -{{- end }} + components, err := state.resourceXpathComponents() + if err != nil { + resp.Diagnostics.AddError("Error creating resource xpath", err.Error()) + return + } + + obj, err := r.manager.Read(ctx, location, components) if err != nil { resp.Diagnostics.AddError("Error in update", err.Error()) return @@ -1466,6 +1500,10 @@ type {{ dataSourceStructName }}Filter struct { {{ RenderCopyFromPangoFunctions }} +{{- if not IsResourcePlural }} +{{ RenderXpathComponentsGetter }} +{{- end }} + {{ RenderDataSourceSchema }} func {{ dataSourceStructName }}LocationSchema() rsschema.Attribute { diff --git a/pkg/translate/terraform_provider/terraform_provider_file.go b/pkg/translate/terraform_provider/terraform_provider_file.go index 6e42fd65..10619c86 100644 --- a/pkg/translate/terraform_provider/terraform_provider_file.go +++ b/pkg/translate/terraform_provider/terraform_provider_file.go @@ -127,8 +127,18 @@ func (g *GenerateTerraformProvider) GenerateTerraformResource(resourceTyp proper } funcMap := template.FuncMap{ - "GoSDKSkipped": func() bool { return spec.GoSdkSkip }, - "IsEntry": func() bool { return spec.HasEntryName() && !spec.HasEntryUuid() }, + "GoSDKSkipped": func() bool { return spec.GoSdkSkip }, + "IsEntry": func() bool { return spec.HasEntryName() && !spec.HasEntryUuid() }, + "IsResourcePlural": func() bool { + switch resourceTyp { + case properties.ResourceEntryPlural, properties.ResourceUuid, properties.ResourceUuidPlural: + return true + case properties.ResourceEntry, properties.ResourceConfig, properties.ResourceCustom: + return false + } + + panic("unreachable") + }, "HasImports": func() bool { return len(spec.Imports) > 0 }, "IsCustom": func() bool { return spec.TerraformProviderConfig.ResourceType == properties.TerraformResourceCustom }, "IsUuid": func() bool { return spec.HasEntryUuid() }, @@ -153,6 +163,9 @@ func (g *GenerateTerraformProvider) GenerateTerraformResource(resourceTyp proper "RenderCopyFromPangoFunctions": func() (string, error) { return RenderCopyFromPangoFunctions(resourceTyp, names.PackageName, names.ResourceStructName, spec) }, + "RenderXpathComponentsGetter": func() (string, error) { + return RenderXpathComponentsGetter(names.ResourceStructName, spec) + }, "ResourceCreateFunction": func(structName string, serviceName string) (string, error) { return ResourceCreateFunction(resourceTyp, names, serviceName, spec, terraformProvider, names.PackageName) }, @@ -185,6 +198,7 @@ func (g *GenerateTerraformProvider) GenerateTerraformResource(resourceTyp proper if !spec.TerraformProviderConfig.SkipResource { terraformProvider.ImportManager.AddStandardImport("context", "") terraformProvider.ImportManager.AddSdkImport("github.com/PaloAltoNetworks/pango", "") + if spec.TerraformProviderConfig.ResourceType != properties.TerraformResourceCustom { terraformProvider.ImportManager.AddOtherImport("github.com/PaloAltoNetworks/terraform-provider-panos/internal/manager", "sdkmanager") } @@ -208,6 +222,12 @@ func (g *GenerateTerraformProvider) GenerateTerraformResource(resourceTyp proper case properties.ResourceCustom, properties.ResourceConfig: } + switch resourceTyp { + case properties.ResourceEntry, properties.ResourceConfig: + terraformProvider.ImportManager.AddSdkImport("github.com/PaloAltoNetworks/pango/util", "pangoutil") + case properties.ResourceEntryPlural, properties.ResourceUuid, properties.ResourceUuidPlural, properties.ResourceCustom: + } + // Generate Resource with entry style terraformProvider.ImportManager.AddStandardImport("fmt", "") @@ -246,6 +266,7 @@ func (g *GenerateTerraformProvider) GenerateTerraformResource(resourceTyp proper case properties.ResourceEntryPlural, properties.ResourceUuid: case properties.ResourceUuidPlural, properties.ResourceCustom: } + conditionallyAddValidators(terraformProvider.ImportManager, spec) conditionallyAddModifiers(terraformProvider.ImportManager, spec) conditionallyAddDefaults(terraformProvider.ImportManager, spec.Spec) @@ -291,8 +312,18 @@ func (g *GenerateTerraformProvider) GenerateTerraformDataSource(resourceTyp prop names := NewNameProvider(spec, resourceTyp) funcMap := template.FuncMap{ - "GoSDKSkipped": func() bool { return spec.GoSdkSkip }, - "IsEntry": func() bool { return spec.HasEntryName() && !spec.HasEntryUuid() }, + "GoSDKSkipped": func() bool { return spec.GoSdkSkip }, + "IsEntry": func() bool { return spec.HasEntryName() && !spec.HasEntryUuid() }, + "IsResourcePlural": func() bool { + switch resourceTyp { + case properties.ResourceEntryPlural, properties.ResourceUuid, properties.ResourceUuidPlural: + return true + case properties.ResourceEntry, properties.ResourceConfig, properties.ResourceCustom: + return false + } + + panic("unreachable") + }, "HasImports": func() bool { return len(spec.Imports) > 0 }, "IsCustom": func() bool { return spec.TerraformProviderConfig.ResourceType == properties.TerraformResourceCustom }, "IsUuid": func() bool { return spec.HasEntryUuid() }, @@ -312,6 +343,9 @@ func (g *GenerateTerraformProvider) GenerateTerraformDataSource(resourceTyp prop "RenderCopyFromPangoFunctions": func() (string, error) { return RenderCopyFromPangoFunctions(resourceTyp, names.PackageName, names.DataSourceStructName, spec) }, + "RenderXpathComponentsGetter": func() (string, error) { + return RenderXpathComponentsGetter(names.DataSourceStructName, spec) + }, "RenderDataSourceStructs": func() (string, error) { return RenderDataSourceStructs(resourceTyp, names, spec) }, "RenderDataSourceSchema": func() (string, error) { return RenderDataSourceSchema(resourceTyp, names, spec, terraformProvider.ImportManager) diff --git a/specs/network/subinterface/ethernet/layer3.yaml b/specs/network/subinterface/ethernet/layer3.yaml new file mode 100644 index 00000000..9022fe6e --- /dev/null +++ b/specs/network/subinterface/ethernet/layer3.yaml @@ -0,0 +1,2594 @@ +name: ethernet-layer3-subinterface +terraform_provider_config: + description: Ethernet Layer3 Subinterface + skip_resource: false + skip_datasource: false + resource_type: entry + resource_variants: + - singular + suffix: ethernet_layer3_subinterface + plural_suffix: '' + plural_name: '' + plural_description: '' +go_sdk_config: + skip: false + package: + - network + - subinterface + - ethernet + - layer3 +panos_xpath: + path: + - network + - interface + - ethernet + - $parent + - layer3 + - units + - $name + vars: + - name: parent + spec: + type: value + xpath: /params[@name="parent"] + - name: name + spec: + type: value + xpath: /params[@name="name"] +locations: +- name: shared + xpath: + path: + - config + - shared + vars: [] + description: Location in Shared Panorama + devices: + - panorama + - ngfw + validators: [] + required: false + read_only: false +- name: template + xpath: + path: + - config + - devices + - $panorama_device + - template + - $template + - config + - devices + - $ngfw_device + vars: + - name: panorama_device + description: Specific Panorama device + required: false + default: localhost.localdomain + validators: [] + type: entry + - name: template + description: Specific Panorama template + required: true + validators: [] + type: entry + - name: ngfw_device + description: The NGFW device + required: false + default: localhost.localdomain + validators: [] + type: entry + description: Located in a specific template + devices: + - panorama + validators: [] + required: false + read_only: false +- name: template-stack + xpath: + path: + - config + - devices + - $panorama_device + - template-stack + - $template_stack + - config + - devices + - $ngfw_device + vars: + - name: panorama_device + description: Specific Panorama device + required: false + default: localhost.localdomain + validators: [] + type: entry + - name: template_stack + description: Specific Panorama template stack + required: true + validators: [] + type: entry + - name: ngfw_device + description: The NGFW device + required: false + default: localhost.localdomain + validators: [] + type: entry + description: Located in a specific template stack + devices: + - panorama + validators: [] + required: false + read_only: false +- name: ngfw + xpath: + path: + - config + - devices + - $ngfw_device + vars: + - name: ngfw_device + description: The NGFW device + required: false + default: localhost.localdomain + validators: [] + type: entry + description: Located in a specific NGFW device + devices: + - ngfw + validators: [] + required: false + read_only: false +entries: +- name: name + description: '' + validators: [] +imports: [] +spec: + params: + - name: adjust-tcp-mss + type: object + profiles: + - xpath: + - adjust-tcp-mss + validators: [] + spec: + params: + - name: enable + type: bool + profiles: + - xpath: + - enable + validators: [] + spec: {} + description: Set if TCP MSS value should be reduced based on mtu + required: false + - name: ipv4-mss-adjustment + type: int64 + profiles: + - xpath: + - ipv4-mss-adjustment + validators: + - type: length + spec: + min: 40 + max: 300 + spec: + default: 40 + description: IPv4 MSS adjustment size (in bytes) + required: false + - name: ipv6-mss-adjustment + type: int64 + profiles: + - xpath: + - ipv6-mss-adjustment + validators: + - type: length + spec: + min: 60 + max: 300 + spec: + default: 60 + description: IPv6 MSS adjustment size (in bytes) + required: false + variants: [] + description: TCP MSS adjustment configuration + required: false + - name: arp + type: list + profiles: + - xpath: + - arp + - entry + type: entry + validators: [] + spec: + type: object + items: + type: object + spec: + params: + - name: hw-address + type: string + profiles: + - xpath: + - hw-address + validators: [] + spec: {} + description: MAC address (format xx:xx:xx:xx:xx:xx) + required: false + variants: [] + description: '' + required: false + - name: bonjour + type: object + profiles: + - xpath: + - bonjour + validators: [] + spec: + params: + - name: enable + type: bool + profiles: + - xpath: + - enable + validators: [] + spec: {} + description: Set to support Bonjour service + required: false + - name: group-id + type: int64 + profiles: + - xpath: + - group-id + validators: + - type: length + spec: + min: 0 + max: 16 + spec: + default: 40 + description: 'default 0: NO-Group' + required: false + - name: ttl-check + type: bool + profiles: + - xpath: + - ttl-check + validators: [] + spec: {} + description: Set to check and update TTL + required: false + variants: [] + description: Bonjour configuration + required: false + - name: comment + type: string + profiles: + - xpath: + - comment + validators: + - type: length + spec: + max: 1024 + spec: {} + description: '' + required: false + - name: ddns-config + type: object + profiles: + - xpath: + - ddns-config + validators: [] + spec: + params: + - name: ddns-cert-profile + type: string + profiles: + - xpath: + - ddns-cert-profile + validators: [] + spec: {} + description: '' + required: false + - name: ddns-enabled + type: bool + profiles: + - xpath: + - ddns-enabled + validators: [] + spec: {} + description: '' + required: false + - name: ddns-hostname + type: string + profiles: + - xpath: + - ddns-hostname + validators: + - type: length + spec: + min: 1 + max: 255 + spec: {} + description: ddns hostname variable or real address + required: false + - name: ddns-ip + type: list + profiles: + - xpath: + - ddns-ip + type: member + validators: [] + spec: + type: string + items: + type: string + description: '' + required: false + - name: ddns-ipv6 + type: list + profiles: + - xpath: + - ddns-ipv6 + type: member + validators: [] + spec: + type: string + items: + type: string + description: '' + required: false + - name: ddns-update-interval + type: int64 + profiles: + - xpath: + - ddns-update-interval + validators: + - type: length + spec: + min: 1 + max: 30 + spec: + default: 1 + description: '' + required: false + - name: ddns-vendor + type: string + profiles: + - xpath: + - ddns-vendor + validators: + - type: length + spec: + max: 127 + spec: {} + description: Vendor and product type + required: false + - name: ddns-vendor-config + type: list + profiles: + - xpath: + - ddns-vendor-config + - entry + type: entry + validators: [] + spec: + type: object + items: + type: object + spec: + params: + - name: value + type: string + profiles: + - xpath: + - value + validators: + - type: length + spec: + max: 255 + spec: {} + description: '' + required: false + variants: [] + description: '' + required: false + variants: [] + description: '' + required: false + - name: decrypt-forward + type: bool + profiles: + - xpath: + - decrypt-forward + validators: [] + spec: {} + description: '' + required: false + - name: df-ignore + type: bool + profiles: + - xpath: + - df-ignore + validators: [] + spec: {} + description: '' + required: false + - name: dhcp-client + type: object + profiles: + - xpath: + - dhcp-client + validators: [] + spec: + params: + - name: create-default-route + type: bool + profiles: + - xpath: + - create-default-route + validators: [] + spec: {} + description: Automatically create default route pointing to default gateway + provided by server + required: false + - name: default-route-metric + type: int64 + profiles: + - xpath: + - default-route-metric + validators: + - type: length + spec: + min: 1 + max: 65535 + spec: + default: 10 + description: Metric of the default route created + required: false + - name: enable + type: bool + profiles: + - xpath: + - enable + validators: [] + spec: {} + description: '' + required: false + - name: send-hostname + type: object + profiles: + - xpath: + - send-hostname + validators: [] + spec: + params: + - name: enable + type: bool + profiles: + - xpath: + - enable + validators: [] + spec: {} + description: '' + required: false + - name: hostname + type: string + profiles: + - xpath: + - hostname + validators: [] + spec: + default: system-hostname + description: Set Interface Hostname + required: false + variants: [] + description: Enable send firewall or custom hostname to DHCP server + required: false + variants: [] + description: dhcp client configuration + required: false + - name: interface-management-profile + type: string + profiles: + - xpath: + - interface-management-profile + validators: + - type: length + spec: + max: 31 + spec: {} + description: Interface management profile + required: false + - name: ip + type: list + profiles: + - xpath: + - ip + - entry + type: entry + validators: [] + spec: + type: object + items: + type: object + spec: + params: + - name: sdwan-gateway + type: string + profiles: + - xpath: + - sdwan-gateway + validators: [] + spec: {} + description: Gateway IPv4 Address + required: false + variants: [] + description: '' + required: false + - name: ipv6 + type: object + profiles: + - xpath: + - ipv6 + validators: [] + spec: + params: + - name: address + type: list + profiles: + - xpath: + - address + - entry + type: entry + validators: [] + spec: + type: object + items: + type: object + spec: + params: + - name: enable-on-interface + type: bool + profiles: + - xpath: + - enable-on-interface + validators: [] + spec: {} + description: configure this address on interface + required: false + - name: prefix + type: object + profiles: + - xpath: + - prefix + validators: [] + spec: + params: [] + variants: [] + description: use this as prefix to form full address with interface + id/EUI-64 + required: false + - name: anycast + type: object + profiles: + - xpath: + - anycast + validators: [] + spec: + params: [] + variants: [] + description: anycast address + required: false + - name: advertise + type: object + profiles: + - xpath: + - advertise + validators: [] + spec: + params: + - name: enable + type: bool + profiles: + - xpath: + - enable + validators: [] + spec: {} + description: enable advertising this prefix in router advertisements + required: false + - name: valid-lifetime + type: string + profiles: + - xpath: + - valid-lifetime + validators: [] + spec: + default: '2592000' + description: Valid Lifetime (in seconds) of the prefix advertised + in Router Advertisement messages + required: false + - name: preferred-lifetime + type: string + profiles: + - xpath: + - preferred-lifetime + validators: [] + spec: + default: '604800' + description: Preferred Lifetime (in seconds) of the prefix advertised + in Router Advertisement messages + required: false + - name: onlink-flag + type: bool + profiles: + - xpath: + - onlink-flag + validators: [] + spec: {} + description: Set the On-Link Flag (L-bit) of the prefix in Router + Advertisement messages + required: false + - name: auto-config-flag + type: bool + profiles: + - xpath: + - auto-config-flag + validators: [] + spec: {} + description: Set the Auto Address Configuration Flag (A-bit) of + the prefix in Router Advertisement messages + required: false + variants: [] + description: configure router advertisement prefix option + required: false + variants: [] + description: '' + required: false + - name: enabled + type: bool + profiles: + - xpath: + - enabled + validators: [] + spec: {} + description: Enable IPv6 on the interface + required: false + - name: interface-id + type: string + profiles: + - xpath: + - interface-id + validators: [] + spec: + default: EUI-64 + description: '' + required: false + - name: neighbor-discovery + type: object + profiles: + - xpath: + - neighbor-discovery + validators: [] + spec: + params: + - name: dad-attempts + type: int64 + profiles: + - xpath: + - dad-attempts + validators: + - type: length + spec: + min: 0 + max: 10 + spec: + default: 1 + description: number of consecutive neighbor solicitation messages sent + for duplicate address detection + required: false + - name: enable-dad + type: bool + profiles: + - xpath: + - enable-dad + validators: [] + spec: {} + description: enable duplicate address detection + required: false + - name: enable-ndp-monitor + type: bool + profiles: + - xpath: + - enable-ndp-monitor + validators: [] + spec: {} + description: enable ndp monitoring + required: false + - name: neighbor + type: list + profiles: + - xpath: + - neighbor + - entry + type: entry + validators: [] + spec: + type: object + items: + type: object + spec: + params: + - name: hw-address + type: string + profiles: + - xpath: + - hw-address + validators: [] + spec: {} + description: MAC address (format xx:xx:xx:xx:xx:xx) + required: false + variants: [] + description: '' + required: false + - name: ns-interval + type: int64 + profiles: + - xpath: + - ns-interval + validators: + - type: length + spec: + min: 1 + max: 3600 + spec: + default: 1 + description: interval (in seconds) between consecutive neighbor solicitation + messages + required: false + - name: reachable-time + type: int64 + profiles: + - xpath: + - reachable-time + validators: + - type: length + spec: + min: 10 + max: 36000 + spec: + default: 30 + description: time (in seconds) that the Reachable status for a neighbor + can be maintained + required: false + - name: router-advertisement + type: object + profiles: + - xpath: + - router-advertisement + validators: [] + spec: + params: + - name: dns-support + type: object + profiles: + - xpath: + - dns-support + validators: [] + spec: + params: + - name: enable + type: bool + profiles: + - xpath: + - enable + validators: [] + spec: {} + description: '' + required: false + - name: server + type: list + profiles: + - xpath: + - server + - entry + type: entry + validators: [] + spec: + type: object + items: + type: object + spec: + params: + - name: lifetime + type: int64 + profiles: + - xpath: + - lifetime + validators: + - type: length + spec: + min: 4 + max: 3600 + spec: + default: 1200 + description: (4-3600) lifetime in seconds + required: false + variants: [] + description: '' + required: false + - name: suffix + type: list + profiles: + - xpath: + - suffix + - entry + type: entry + validators: [] + spec: + type: object + items: + type: object + spec: + params: + - name: lifetime + type: int64 + profiles: + - xpath: + - lifetime + validators: + - type: length + spec: + min: 4 + max: 3600 + spec: + default: 1200 + description: (4-3600) lifetime in seconds + required: false + variants: [] + description: '' + required: false + variants: [] + description: DNS configuration support + required: false + - name: enable + type: bool + profiles: + - xpath: + - enable + validators: [] + spec: {} + description: '' + required: false + - name: enable-consistency-check + type: bool + profiles: + - xpath: + - enable-consistency-check + validators: [] + spec: {} + description: check consistency of RA messages from other routers. + required: false + - name: hop-limit + type: string + profiles: + - xpath: + - hop-limit + validators: [] + spec: + default: '64' + description: Current Hop Limit advertised in Router Advertisement + messages + required: false + - name: lifetime + type: int64 + profiles: + - xpath: + - lifetime + validators: + - type: length + spec: + min: 0 + max: 9000 + spec: + default: 1800 + description: Router Lifetime (in seconds) advertised in Router Advertisement + messages + required: false + - name: link-mtu + type: string + profiles: + - xpath: + - link-mtu + validators: [] + spec: + default: unspecified + description: value of MTU option in Router Advertisement messages, + upto 9216 in Jumbo-Frame mode, up to 1500 otherwise + required: false + - name: managed-flag + type: bool + profiles: + - xpath: + - managed-flag + validators: [] + spec: {} + description: Set the Managed Configuration Flag (M-bit) in Router + Advertisement messages + required: false + - name: max-interval + type: int64 + profiles: + - xpath: + - max-interval + validators: + - type: length + spec: + min: 4 + max: 1800 + spec: + default: 600 + description: Maximum interval (seconds) between consecutive unsolicited + Router Advertisement messages + required: false + - name: min-interval + type: int64 + profiles: + - xpath: + - min-interval + validators: + - type: length + spec: + min: 3 + max: 1350 + spec: + default: 200 + description: Minimum interval (seconds) between consecutive unsolicited + Router Advertisement messages + required: false + - name: other-flag + type: bool + profiles: + - xpath: + - other-flag + validators: [] + spec: {} + description: Set the Other Stateful Configuration Flag (O-bit) in + Router Advertisement messages + required: false + - name: reachable-time + type: string + profiles: + - xpath: + - reachable-time + validators: [] + spec: + default: unspecified + description: Reachable Time (in milliseconds) advertised in Router + Advertisement messages + required: false + - name: retransmission-timer + type: string + profiles: + - xpath: + - retransmission-timer + validators: [] + spec: + default: unspecified + description: Retransmission Timer (in milliseconds) advertised in + Router Advertisement messages + required: false + - name: router-preference + type: enum + profiles: + - xpath: + - router-preference + validators: + - type: values + spec: + values: + - High + - Medium + - Low + spec: + default: Medium + values: + - value: High + - value: Medium + - value: Low + description: '' + required: false + variants: [] + description: Router advertisement configuration + required: false + variants: [] + description: Neighbor Discovery configuration + required: false + - name: dhcp-client + type: object + profiles: + - xpath: + - dhcp-client + validators: [] + spec: + params: + - name: accept-ra-route + type: bool + profiles: + - xpath: + - accept-ra-route + validators: [] + spec: {} + description: Accept Router Advertised Default Route + required: false + - name: default-route-metric + type: int64 + profiles: + - xpath: + - default-route-metric + validators: + - type: length + spec: + min: 1 + max: 65535 + spec: + default: 10 + description: Metric of the default route created + required: false + - name: enable + type: bool + profiles: + - xpath: + - enable + validators: [] + spec: {} + description: Enable DHCPv6 Client + required: false + - name: neighbor-discovery + type: object + profiles: + - xpath: + - neighbor-discovery + validators: [] + spec: + params: + - name: dad-attempts + type: int64 + profiles: + - xpath: + - dad-attempts + validators: + - type: length + spec: + min: 1 + max: 10 + spec: + default: 1 + description: number of consecutive neighbor solicitation messages + sent for duplicate address detection + required: false + - name: dns-server + type: object + profiles: + - xpath: + - dns-server + validators: [] + spec: + params: + - name: enable + type: bool + profiles: + - xpath: + - enable + validators: [] + spec: {} + description: '' + required: false + - name: source + type: object + profiles: + - xpath: + - source + validators: [] + spec: + params: [] + variants: + - name: dhcpv6 + type: object + profiles: + - xpath: + - dhcpv6 + validators: [] + spec: + params: [] + variants: [] + description: Source from DHCPv6 Server + required: false + - name: manual + type: object + profiles: + - xpath: + - manual + validators: [] + spec: + params: + - name: server + type: list + profiles: + - xpath: + - server + - entry + type: entry + validators: [] + spec: + type: object + items: + type: object + spec: + params: + - name: lifetime + type: int64 + profiles: + - xpath: + - lifetime + validators: + - type: length + spec: + min: 4 + max: 3600 + spec: + default: 1200 + description: (4-3600) Lifetime in Seconds + required: false + variants: [] + description: '' + required: false + variants: [] + description: Configure manually + required: false + description: Either source from DHCPv6 Server or manually configure + required: false + variants: [] + description: DNS Recursive Name Server + required: false + - name: dns-suffix + type: object + profiles: + - xpath: + - dns-suffix + validators: [] + spec: + params: + - name: enable + type: bool + profiles: + - xpath: + - enable + validators: [] + spec: {} + description: '' + required: false + - name: source + type: object + profiles: + - xpath: + - source + validators: [] + spec: + params: [] + variants: + - name: dhcpv6 + type: object + profiles: + - xpath: + - dhcpv6 + validators: [] + spec: + params: [] + variants: [] + description: Source from DHCPv6 Server + required: false + - name: manual + type: object + profiles: + - xpath: + - manual + validators: [] + spec: + params: + - name: suffix + type: list + profiles: + - xpath: + - suffix + - entry + type: entry + validators: [] + spec: + type: object + items: + type: object + spec: + params: + - name: lifetime + type: int64 + profiles: + - xpath: + - lifetime + validators: + - type: length + spec: + min: 4 + max: 3600 + spec: + default: 1200 + description: (4-3600) lifetime in seconds + required: false + variants: [] + description: '' + required: false + variants: [] + description: Configure manually + required: false + description: Either source from DHCPv6 Server or manually configure + required: false + variants: [] + description: Domain Search List + required: false + - name: enable-dad + type: bool + profiles: + - xpath: + - enable-dad + validators: [] + spec: {} + description: Enable Duplicate Address Detection + required: false + - name: enable-ndp-monitor + type: bool + profiles: + - xpath: + - enable-ndp-monitor + validators: [] + spec: {} + description: Enable NDP Monitoring + required: false + - name: neighbor + type: list + profiles: + - xpath: + - neighbor + - entry + type: entry + validators: [] + spec: + type: object + items: + type: object + spec: + params: + - name: hw-address + type: string + profiles: + - xpath: + - hw-address + validators: [] + spec: {} + description: MAC address (format xx:xx:xx:xx:xx:xx) + required: false + variants: [] + description: '' + required: false + - name: ns-interval + type: int64 + profiles: + - xpath: + - ns-interval + validators: + - type: length + spec: + min: 1 + max: 3600 + spec: + default: 1 + description: interval (in seconds) between consecutive neighbor solicitation + messages + required: false + - name: reachable-time + type: int64 + profiles: + - xpath: + - reachable-time + validators: + - type: length + spec: + min: 10 + max: 36000 + spec: + default: 30 + description: time (in seconds) that the Reachable status for a neighbor + can be maintained + required: false + variants: [] + description: Neighbor Discovery configuration + required: false + - name: preference + type: enum + profiles: + - xpath: + - preference + validators: + - type: values + spec: + values: + - low + - medium + - high + spec: + default: high + values: + - value: low + - value: medium + - value: high + description: Select Low/Medium/High + required: false + - name: prefix-delegation + type: object + profiles: + - xpath: + - prefix-delegation + validators: [] + spec: + params: + - name: enable + type: object + profiles: + - xpath: + - enable + validators: [] + spec: + params: [] + variants: + - name: 'no' + type: object + profiles: + - xpath: + - 'no' + validators: [] + spec: + params: [] + variants: [] + description: Disable Prefix Delegation + required: false + - name: 'yes' + type: object + profiles: + - xpath: + - 'yes' + validators: [] + spec: + params: + - name: pfx-pool-name + type: string + profiles: + - xpath: + - pfx-pool-name + validators: + - type: length + spec: + max: 63 + spec: {} + description: Configure unique Prefix Pool Name + required: false + - name: prefix-len + type: int64 + profiles: + - xpath: + - prefix-len + validators: + - type: length + spec: + min: 0 + max: 128 + spec: + default: 48 + description: Hint DHCP Prefix Length (bits) + required: false + - name: prefix-len-hint + type: bool + profiles: + - xpath: + - prefix-len-hint + validators: [] + spec: {} + description: Send prefix length hint to server + required: false + variants: [] + description: Enable Prefix Delegation + required: false + description: Enable/Disable Prefix Delegation + required: false + variants: [] + description: Configure Prefix Delegation Options + required: false + - name: v6-options + type: object + profiles: + - xpath: + - v6-options + validators: [] + spec: + params: + - name: duid-type + type: enum + profiles: + - xpath: + - duid-type + validators: + - type: values + spec: + values: + - duid-type-llt + - duid-type-ll + spec: + default: duid-type-llt + values: + - value: duid-type-llt + - value: duid-type-ll + description: Select DUID-LLT/DUID-LL + required: false + - name: enable + type: object + profiles: + - xpath: + - enable + validators: [] + spec: + params: [] + variants: + - name: 'no' + type: object + profiles: + - xpath: + - 'no' + validators: [] + spec: + params: [] + variants: [] + description: Disable IPv6 Address + required: false + - name: 'yes' + type: object + profiles: + - xpath: + - 'yes' + validators: [] + spec: + params: + - name: non-temp-addr + type: bool + profiles: + - xpath: + - non-temp-addr + validators: [] + spec: {} + description: Request Non-Temporary Address Type + required: false + - name: temp-addr + type: bool + profiles: + - xpath: + - temp-addr + validators: [] + spec: {} + description: Request Temporary Address Type + required: false + variants: [] + description: Enable IPv6 Address + required: false + description: Enable/Disable IPv6 Address + required: false + - name: rapid-commit + type: bool + profiles: + - xpath: + - rapid-commit + validators: [] + spec: {} + description: Enable Rapid Commit + required: false + - name: support-srvr-reconfig + type: bool + profiles: + - xpath: + - support-srvr-reconfig + validators: [] + spec: {} + description: Enable DHCPv6 Server Re-Configuration Support + required: false + variants: [] + description: Configure DHCPv6 Options + required: false + variants: [] + description: Configure DHCPv6 Client + required: false + - name: inherited + type: object + profiles: + - xpath: + - inherited + validators: [] + spec: + params: + - name: assign-addr + type: list + profiles: + - xpath: + - assign-addr + - entry + type: entry + validators: [] + spec: + type: object + items: + type: object + spec: + params: + - name: type + type: object + profiles: + - xpath: + - type + validators: [] + spec: + params: [] + variants: + - name: gua + type: object + profiles: + - xpath: + - gua + validators: [] + spec: + params: + - name: enable-on-interface + type: bool + profiles: + - xpath: + - enable-on-interface + validators: [] + spec: {} + description: Enable on Interface + required: false + - name: prefix-pool + type: string + profiles: + - xpath: + - prefix-pool + validators: + - type: length + spec: + max: 63 + spec: {} + description: Prefix-Pool Name + required: false + - name: pool-type + type: object + profiles: + - xpath: + - pool-type + validators: [] + spec: + params: [] + variants: + - name: dynamic + type: object + profiles: + - xpath: + - dynamic + validators: [] + spec: + params: [] + variants: [] + description: Dynamically allocate Pool to member Interfaces + required: false + - name: dynamic-id + type: object + profiles: + - xpath: + - dynamic-id + validators: [] + spec: + params: + - name: identifier + type: int64 + profiles: + - xpath: + - identifier + validators: + - type: length + spec: + min: 0 + max: 4095 + spec: {} + description: Range [0-4095] must be unqiue for + this prefix-pool + required: false + variants: [] + description: Assign Id to selected delegate prefix + from the pool + required: false + description: Select Pool Allocation Method + required: false + - name: advertise + type: object + profiles: + - xpath: + - advertise + validators: [] + spec: + params: + - name: enable + type: bool + profiles: + - xpath: + - enable + validators: [] + spec: {} + description: Enable advertising this prefix in router + advertisements + required: false + - name: onlink-flag + type: bool + profiles: + - xpath: + - onlink-flag + validators: [] + spec: {} + description: Set the On-Link Flag (L-bit) of the prefix + in Router Advertisement messages + required: false + - name: auto-config-flag + type: bool + profiles: + - xpath: + - auto-config-flag + validators: [] + spec: {} + description: Set the Auto Address Configuration Flag + (A-bit) of the prefix in Router Advertisement messages + required: false + variants: [] + description: Configure router advertisement prefix options + required: false + variants: [] + description: Select GUA (Global Unique Address)from Pool + required: false + - name: ula + type: object + profiles: + - xpath: + - ula + validators: [] + spec: + params: + - name: enable-on-interface + type: bool + profiles: + - xpath: + - enable-on-interface + validators: [] + spec: {} + description: Configure this address on Interface + required: false + - name: address + type: string + profiles: + - xpath: + - address + validators: [] + spec: {} + description: Configure ULA (Unique Local Address) + required: false + - name: prefix + type: bool + profiles: + - xpath: + - prefix + validators: [] + spec: {} + description: Use this as prefix to form full address with + interface id/EUI-64 + required: false + - name: anycast + type: bool + profiles: + - xpath: + - anycast + validators: [] + spec: {} + description: Anycast Address + required: false + - name: advertise + type: object + profiles: + - xpath: + - advertise + validators: [] + spec: + params: + - name: enable + type: bool + profiles: + - xpath: + - enable + validators: [] + spec: {} + description: enable advertising this prefix in router + advertisements + required: false + - name: valid-lifetime + type: string + profiles: + - xpath: + - valid-lifetime + validators: [] + spec: + default: '2592000' + description: Valid Lifetime (in seconds) of the prefix + advertised in Router Advertisement messages + required: false + - name: preferred-lifetime + type: string + profiles: + - xpath: + - preferred-lifetime + validators: [] + spec: + default: '604800' + description: Preferred Lifetime (in seconds) of the + prefix advertised in Router advertisement messages + required: false + - name: onlink-flag + type: bool + profiles: + - xpath: + - onlink-flag + validators: [] + spec: {} + description: Set the On-Link Flag (L-bit) of the prefix + in Router Advertisement messages + required: false + - name: auto-config-flag + type: bool + profiles: + - xpath: + - auto-config-flag + validators: [] + spec: {} + description: Set the Auto Address Configuration Flag + (A-bit) of the prefix in Router Advertisement messages + required: false + variants: [] + description: Configure router advertisement prefix options + required: false + variants: [] + description: Configure ULA (Unique Local Address) + required: false + description: Select Address Source Type + required: false + variants: [] + description: '' + required: false + - name: enable + type: bool + profiles: + - xpath: + - enable + validators: [] + spec: {} + description: Enable Inherited Interface + required: false + - name: neighbor-discovery + type: object + profiles: + - xpath: + - neighbor-discovery + validators: [] + spec: + params: + - name: dad-attempts + type: int64 + profiles: + - xpath: + - dad-attempts + validators: + - type: length + spec: + min: 1 + max: 10 + spec: + default: 1 + description: Number of consecutive neighbor solicitation messages + sent for duplicate address detection + required: false + - name: dns-server + type: object + profiles: + - xpath: + - dns-server + validators: [] + spec: + params: + - name: enable + type: bool + profiles: + - xpath: + - enable + validators: [] + spec: {} + description: '' + required: false + - name: source + type: object + profiles: + - xpath: + - source + validators: [] + spec: + params: [] + variants: + - name: dhcpv6 + type: object + profiles: + - xpath: + - dhcpv6 + validators: [] + spec: + params: + - name: prefix-pool + type: string + profiles: + - xpath: + - prefix-pool + validators: + - type: length + spec: + max: 63 + spec: {} + description: Prefix-Pool Name + required: false + variants: [] + description: Source from DHCPv6 Server + required: false + - name: manual + type: object + profiles: + - xpath: + - manual + validators: [] + spec: + params: + - name: server + type: list + profiles: + - xpath: + - server + - entry + type: entry + validators: [] + spec: + type: object + items: + type: object + spec: + params: + - name: lifetime + type: int64 + profiles: + - xpath: + - lifetime + validators: + - type: length + spec: + min: 4 + max: 3600 + spec: + default: 1200 + description: (4-3600) Lifetime in Seconds + required: false + variants: [] + description: '' + required: false + variants: [] + description: Configure manually + required: false + description: Either source from DHCPv6 Server or manually configure + required: false + variants: [] + description: DNS Recursive Name Server + required: false + - name: dns-suffix + type: object + profiles: + - xpath: + - dns-suffix + validators: [] + spec: + params: + - name: enable + type: bool + profiles: + - xpath: + - enable + validators: [] + spec: {} + description: '' + required: false + - name: source + type: object + profiles: + - xpath: + - source + validators: [] + spec: + params: [] + variants: + - name: dhcpv6 + type: object + profiles: + - xpath: + - dhcpv6 + validators: [] + spec: + params: + - name: prefix-pool + type: string + profiles: + - xpath: + - prefix-pool + validators: + - type: length + spec: + max: 63 + spec: {} + description: Prefix-Pool Name + required: false + variants: [] + description: Source from DHCPv6 Server + required: false + - name: manual + type: object + profiles: + - xpath: + - manual + validators: [] + spec: + params: + - name: suffix + type: list + profiles: + - xpath: + - suffix + - entry + type: entry + validators: [] + spec: + type: object + items: + type: object + spec: + params: + - name: lifetime + type: int64 + profiles: + - xpath: + - lifetime + validators: + - type: length + spec: + min: 4 + max: 3600 + spec: + default: 1200 + description: (4-3600) lifetime in seconds + required: false + variants: [] + description: '' + required: false + variants: [] + description: Configure manually + required: false + description: Either source from DHCPv6 Server or manually configure + required: false + variants: [] + description: Domain Search List + required: false + - name: enable-dad + type: bool + profiles: + - xpath: + - enable-dad + validators: [] + spec: {} + description: Enable Duplicate Address Detection (DAD) + required: false + - name: enable-ndp-monitor + type: bool + profiles: + - xpath: + - enable-ndp-monitor + validators: [] + spec: {} + description: Enable NDP Monitoring + required: false + - name: neighbor + type: list + profiles: + - xpath: + - neighbor + - entry + type: entry + validators: [] + spec: + type: object + items: + type: object + spec: + params: + - name: hw-address + type: string + profiles: + - xpath: + - hw-address + validators: [] + spec: {} + description: MAC address (format xx:xx:xx:xx:xx:xx) + required: false + variants: [] + description: '' + required: false + - name: ns-interval + type: int64 + profiles: + - xpath: + - ns-interval + validators: + - type: length + spec: + min: 1 + max: 3600 + spec: + default: 1 + description: Interval (in seconds) between consecutive neighbor solicitation + messages + required: false + - name: reachable-time + type: int64 + profiles: + - xpath: + - reachable-time + validators: + - type: length + spec: + min: 10 + max: 36000 + spec: + default: 30 + description: Time (in seconds) that the Reachable status for a neighbor + can be maintained + required: false + - name: router-advertisement + type: object + profiles: + - xpath: + - router-advertisement + validators: [] + spec: + params: + - name: enable + type: bool + profiles: + - xpath: + - enable + validators: [] + spec: {} + description: '' + required: false + - name: enable-consistency-check + type: bool + profiles: + - xpath: + - enable-consistency-check + validators: [] + spec: {} + description: check consistency of RA messages from other routers. + required: false + - name: hop-limit + type: string + profiles: + - xpath: + - hop-limit + validators: [] + spec: + default: '64' + description: Current Hop Limit advertised in Router Advertisement + messages + required: false + - name: lifetime + type: int64 + profiles: + - xpath: + - lifetime + validators: + - type: length + spec: + min: 0 + max: 9000 + spec: + default: 1800 + description: Router Lifetime (in seconds) advertised in Router + Advertisement messages + required: false + - name: link-mtu + type: string + profiles: + - xpath: + - link-mtu + validators: [] + spec: + default: unspecified + description: value of MTU option in Router Advertisement messages, + upto 9216 in Jumbo-Frame mode, up to 1500 otherwise + required: false + - name: managed-flag + type: bool + profiles: + - xpath: + - managed-flag + validators: [] + spec: {} + description: Set the Managed Configuration Flag (M-bit) in Router + Advertisement messages + required: false + - name: max-interval + type: int64 + profiles: + - xpath: + - max-interval + validators: + - type: length + spec: + min: 4 + max: 1800 + spec: + default: 600 + description: Maximum interval (seconds) between consecutive unsolicited + Router Advertisement messages + required: false + - name: min-interval + type: int64 + profiles: + - xpath: + - min-interval + validators: + - type: length + spec: + min: 3 + max: 1350 + spec: + default: 200 + description: Minimum interval (seconds) between consecutive unsolicited + Router Advertisement messages + required: false + - name: other-flag + type: bool + profiles: + - xpath: + - other-flag + validators: [] + spec: {} + description: Set the Other Stateful Configuration Flag (O-bit) + in Router Advertisement messages + required: false + - name: reachable-time + type: string + profiles: + - xpath: + - reachable-time + validators: [] + spec: + default: unspecified + description: Reachable Time (in milliseconds) advertised in Router + Advertisement messages + required: false + - name: retransmission-timer + type: string + profiles: + - xpath: + - retransmission-timer + validators: [] + spec: + default: unspecified + description: Retransmission Timer (in milliseconds) advertised + in Router Advertisement messages + required: false + - name: router-preference + type: enum + profiles: + - xpath: + - router-preference + validators: + - type: values + spec: + values: + - High + - Medium + - Low + spec: + default: Medium + values: + - value: High + - value: Medium + - value: Low + description: '' + required: false + variants: [] + description: Router Advertisement configuration + required: false + variants: [] + description: Neighbor Discovery configuration + required: false + variants: [] + description: Configure to inherit properties from another interface + required: false + variants: [] + description: Interface IPv6 configuration + required: false + - name: mtu + type: int64 + profiles: + - xpath: + - mtu + validators: + - type: length + spec: + min: 576 + max: 9216 + spec: {} + description: Maximum Transfer Unit, up to 9216 in Jumbo-Frame mode, up to 1500 + otherwise + required: false + - name: ndp-proxy + type: object + profiles: + - xpath: + - ndp-proxy + validators: [] + spec: + params: + - name: address + type: list + profiles: + - xpath: + - address + - entry + type: entry + validators: [] + spec: + type: object + items: + type: object + spec: + params: + - name: negate + type: bool + profiles: + - xpath: + - negate + validators: [] + spec: {} + description: put the prefix or address on a block list + required: false + variants: [] + description: '' + required: false + - name: enabled + type: bool + profiles: + - xpath: + - enabled + validators: [] + spec: {} + description: Enable proxy NDP on the interface + required: false + variants: [] + description: proxy-ndp configuration + required: false + - name: netflow-profile + type: string + profiles: + - xpath: + - netflow-profile + validators: + - type: length + spec: + max: 63 + spec: {} + description: Netflow Server Profile + required: false + - name: sdwan-link-settings + type: object + profiles: + - xpath: + - sdwan-link-settings + validators: [] + spec: + params: + - name: enable + type: bool + profiles: + - xpath: + - enable + validators: [] + spec: {} + description: Enable sdwan on this ethernet interface + required: false + - name: sdwan-interface-profile + type: string + profiles: + - xpath: + - sdwan-interface-profile + validators: + - type: length + spec: + max: 31 + spec: {} + description: Sdwan link characteristics + required: false + - name: upstream-nat + type: object + profiles: + - xpath: + - upstream-nat + validators: [] + spec: + params: + - name: enable + type: bool + profiles: + - xpath: + - enable + validators: [] + spec: {} + description: Enable upstream NAT IP config + required: false + variants: + - name: ddns + type: object + profiles: + - xpath: + - ddns + validators: [] + spec: + params: [] + variants: [] + description: DDNS derives upstream NAT IP + required: false + - name: static-ip + type: object + profiles: + - xpath: + - static-ip + validators: [] + spec: + params: [] + variants: + - name: fqdn + type: string + profiles: + - xpath: + - fqdn + validators: + - type: length + spec: + max: 255 + spec: {} + description: Upstream NAT address FQDN name configuration + required: false + - name: ip-address + type: string + profiles: + - xpath: + - ip-address + validators: [] + spec: {} + description: Upstream NAT IP address + required: false + description: Upstream NAT IP address + required: false + description: Upstream NAT IP config + required: false + variants: [] + description: Sdwan related settings + required: false + - name: tag + type: int64 + profiles: + - xpath: + - tag + validators: + - type: length + spec: + min: 1 + max: 4094 + spec: {} + description: 802.1q VLAN tag + required: false + - name: pppoe + type: object + profiles: + - xpath: + - pppoe + validators: [] + spec: + params: + - name: access-concentrator + type: string + profiles: + - xpath: + - access-concentrator + validators: + - type: length + spec: + min: 1 + max: 255 + spec: {} + description: desired access concentrator. The valid characters are [a-zA-Z0-9._~!@#$%^*(){},:?/+=\-] + required: false + - name: authentication + type: enum + profiles: + - xpath: + - authentication + validators: + - type: values + spec: + values: + - CHAP + - PAP + - auto + spec: + values: + - value: CHAP + - value: PAP + - value: auto + description: authentication protocol + required: false + - name: create-default-route + type: bool + profiles: + - xpath: + - create-default-route + validators: [] + spec: {} + description: automatically create default route pointing to peer + required: false + - name: default-route-metric + type: int64 + profiles: + - xpath: + - default-route-metric + validators: + - type: length + spec: + min: 1 + max: 65535 + spec: + default: 10 + description: metric of the default route created + required: false + - name: enable + type: bool + profiles: + - xpath: + - enable + validators: [] + spec: {} + description: '' + required: false + - name: passive + type: object + profiles: + - xpath: + - passive + validators: [] + spec: + params: + - name: enable + type: bool + profiles: + - xpath: + - enable + validators: [] + spec: {} + description: '' + required: false + variants: [] + description: devices awaits PPP request from peer + required: false + - name: password + type: string + profiles: + - xpath: + - password + validators: + - type: length + spec: + max: 255 + spec: {} + description: password for ppp autentication + required: false + - name: service + type: string + profiles: + - xpath: + - service + validators: + - type: length + spec: + min: 1 + max: 255 + spec: {} + description: desired service. The valid characters are [a-zA-Z0-9._~!@#$%^*(){},:?/+=\-] + required: false + - name: static-address + type: object + profiles: + - xpath: + - static-address + validators: [] + spec: + params: + - name: ip + type: string + profiles: + - xpath: + - ip + validators: + - type: length + spec: + max: 63 + spec: {} + description: static ip address + required: false + variants: [] + description: use static interface address + required: false + - name: username + type: string + profiles: + - xpath: + - username + validators: + - type: length + spec: + min: 1 + max: 255 + spec: {} + description: username for ppp authentication. The valid characters are [a-zA-Z0-9._~!@#$%^*(){},:?/+=\-] + required: false + variants: [] + description: pppoe configuration + required: false + - name: parent + type: string + profiles: + - xpath: [] + codegen_overrides: + gosdk: + skip: true + terraform: + xpath_variable: parent + variants: [] diff --git a/templates/sdk/entry.tmpl b/templates/sdk/entry.tmpl index 73dd66ee..058c2bd4 100644 --- a/templates/sdk/entry.tmpl +++ b/templates/sdk/entry.tmpl @@ -3,7 +3,7 @@ type entryXml{{createGoSuffixFromVersion $.Version}} struct { XMLName xml.Name `xml:"entry"` Name string `xml:"name,attr"` {{- range $_, $param := $.Spec.Params}} - {{- if paramSupportedInVersion $param $.Version}} + {{- if and (paramNotSkipped $param) (paramSupportedInVersion $param $.Version)}} {{- if $param.Spec}} {{$param.Name.CamelCase}} {{xmlParamType "" $param}}{{createGoSuffixFromVersion $.Version}} {{xmlTag $param}} {{- else}} @@ -13,7 +13,7 @@ type entryXml{{createGoSuffixFromVersion $.Version}} struct { {{- end}} {{- range $_, $param := $.Spec.OneOf}} - {{- if paramSupportedInVersion $param $.Version}} + {{- if and (paramNotSkipped $param) (paramSupportedInVersion $param $.Version)}} {{- if $param.Spec}} {{$param.Name.CamelCase}} {{xmlParamType "" $param}}{{createGoSuffixFromVersion $.Version}} {{xmlTag $param}} {{- else}} @@ -32,7 +32,7 @@ type {{ .Name }}Xml{{createGoSuffixFromVersion $.Version}} struct { {{- if eq $param.Name.CamelCase "Name"}} XMLName xml.Name `xml:"entry"` {{- end}} - {{- if paramSupportedInVersion $param $.Version}} + {{- if and (paramNotSkipped $param) (paramSupportedInVersion $param $.Version)}} {{- if $param.Spec}} {{$param.Name.CamelCase}} {{xmlParamType $.Name $param}}{{createGoSuffixFromVersion $.Version}} {{xmlTag $param}} {{- else}} @@ -42,7 +42,7 @@ type {{ .Name }}Xml{{createGoSuffixFromVersion $.Version}} struct { {{- end}} {{- range $_, $param := $.Spec.OneOf}} - {{- if paramSupportedInVersion $param $.Version}} + {{- if and (paramNotSkipped $param) (paramSupportedInVersion $param $.Version)}} {{- if $param.Spec}} {{$param.Name.CamelCase}} {{xmlParamType $.Name $param}}{{createGoSuffixFromVersion $.Version}} {{xmlTag $param}} {{- else}} @@ -84,11 +84,15 @@ func (c *entryXmlContainer{{ createGoSuffixFromVersion $.Version }}) Normalize() } entry.Name = o.Name {{- range $_, $param := $.Spec.Params}} + {{- if paramNotSkipped $param }} {{normalizeAssignment "entry" $param $.Version }} + {{- end }} {{- end}} {{- range $_, $param := $.Spec.OneOf}} + {{- if paramNotSkipped $param }} {{normalizeAssignment "entry" $param $.Version }} + {{- end }} {{- end}} entry.Misc["Entry"] = o.Misc @@ -120,10 +124,14 @@ return entryList, nil type Entry{{createGoSuffixFromVersion nil}} struct { Name string {{- range $_, $param := $.Spec.Params}} + {{- if paramNotSkipped $param }} {{$param.Name.CamelCase}} {{specParamType "" $param}} + {{- end }} {{- end}} {{- range $_, $param := $.Spec.OneOf}} + {{- if paramNotSkipped $param }} {{$param.Name.CamelCase}} {{specParamType "" $param}} + {{- end }} {{- end}} Misc map[string][]generic.Xml @@ -132,10 +140,14 @@ return entryList, nil {{ range $name, $spec := nestedSpecs $.Spec }} type {{$name}}{{createGoSuffixFromVersion nil}} struct { {{- range $_, $param := $spec.Params}} + {{- if paramNotSkipped $param }} {{$param.Name.CamelCase}} {{specParamType $name $param}} + {{- end }} {{- end}} {{- range $_, $param := $spec.OneOf}} + {{- if paramNotSkipped $param }} {{$param.Name.CamelCase}} {{specParamType $name $param}} + {{- end }} {{- end}} } {{- end}} @@ -179,6 +191,9 @@ return entryList, nil } {{- range $_, $param := .Spec.Params}} + {{- if not (paramNotSkipped $param) }} + {{ continue }} + {{- end }} if v == "{{$param.Name.Underscore}}" || v == "{{$param.Name.CamelCase}}" { return e.{{$param.Name.CamelCase}}, nil } @@ -232,11 +247,17 @@ return entryList, nil // Don't compare Name. {{- range $_, $param := .Spec.Params}} + {{- if not (paramNotSkipped $param) }} + {{ continue }} + {{- end }} if !{{specMatchesFunction $param}}(a.{{$param.Name.CamelCase}}, b.{{$param.Name.CamelCase}}) { return false } {{- end}} {{- range $_, $param := .Spec.OneOf}} + {{- if not (paramNotSkipped $param) }} + {{ continue }} + {{- end }} if !{{specMatchesFunction $param}}(a.{{$param.Name.CamelCase}}, b.{{$param.Name.CamelCase}}) { return false } diff --git a/templates/sdk/location.tmpl b/templates/sdk/location.tmpl index d312d9f8..f6a820f0 100644 --- a/templates/sdk/location.tmpl +++ b/templates/sdk/location.tmpl @@ -102,6 +102,21 @@ return nil, errors.NoLocationSpecifiedError return ans, nil } +func (o Location) XpathWithComponents(vn version.Number, components ...string) ([]string, error) { + if len(components) != {{ .ResourceXpathVariablesCount }} { + return nil, fmt.Errorf("invalid number of arguments for Xpath() call") + } + + ans, err := o.XpathPrefix(vn) + if err != nil { + return nil, err + } + + ans = append(ans, {{ .ResourceXpathAssigments }}) + + return ans, nil +} + {{- if .Entry}} func (o Location) XpathWithEntryName(vn version.Number, name string) ([]string, error) { {{- else}} diff --git a/templates/sdk/service.tmpl b/templates/sdk/service.tmpl index 9331048a..b4628517 100644 --- a/templates/sdk/service.tmpl +++ b/templates/sdk/service.tmpl @@ -55,73 +55,91 @@ client: client, } // Create adds new item, then returns the result. -{{- if and (.Entry) (.Imports)}} - func (s *Service) Create(ctx context.Context, loc Location, importLocations []ImportLocation, entry *Entry) (*Entry, error) { -{{- else if (.Entry) }} - func (s *Service) Create(ctx context.Context, loc Location, entry *Entry) (*Entry, error) { -{{- else }} - func (s *Service) Create(ctx context.Context, loc Location, config *Config) (*Config, error) { -{{- end}} + {{- if and (.Entry) (.Imports)}} +func (s *Service) Create(ctx context.Context, loc Location, importLocations []ImportLocation, entry *Entry) (*Entry, error) { + {{- else if (.Entry) }} +func (s *Service) Create(ctx context.Context, loc Location, entry *Entry) (*Entry, error) { + {{- else }} +func (s *Service) Create(ctx context.Context, loc Location, config *Config) (*Config, error) { + {{- end}} -{{- if .Entry}} - if entry.Name == "" { - return nil, errors.NameNotSpecifiedError - } -{{- end}} + {{- if .Entry}} + if entry.Name == "" { + return nil, errors.NameNotSpecifiedError + } + {{- end}} -vn := s.client.Versioning() + vn := s.client.Versioning() -specifier, _, err := Versioning(vn) -if err != nil { -return nil, err -} + {{- if .Entry}} + path, err := loc.XpathWithEntryName(vn, entry.Name) + {{- else}} + path, err := loc.Xpath(vn) + {{- end}} + if err != nil { + return nil, err + } -{{- if .Entry}} - path, err := loc.XpathWithEntryName(vn, entry.Name) -{{- else}} - path, err := loc.Xpath(vn) -{{- end}} -if err != nil { -return nil, err -} + {{- if .Entry}} + err = s.CreateWithXpath(ctx, util.AsXpath(path[:len(path)-1]), entry) + {{- else}} + err = s.CreateWithXpath(ctx, util.AsXpath(path[:len(path)-1]), config) + {{- end}} + if err != nil { + return nil, err + } -{{- if .Entry}} - createSpec, err := specifier(entry) -{{- else}} - createSpec, err := specifier(config) -{{- end}} -if err != nil { -return nil, err -} + {{- if .Imports }} + err = s.ImportToLocations(ctx, loc, importLocations, entry.Name) + if err != nil { + return nil, err + } + {{- end }} -cmd := &xmlapi.Config{ -Action: "set", -Xpath: util.AsXpath(path[:len(path)-1]), -Element: createSpec, -Target: s.client.GetTarget(), + return s.ReadWithXpath(ctx, util.AsXpath(path), "get") } -if _, _, err = s.client.Communicate(ctx, cmd, false, nil); err != nil { -return nil, err -} -{{- if .Imports }} -err = s.importToLocations(ctx, loc, importLocations, entry.Name) -if err != nil { - return nil, err -} -{{- end }} + {{ $funcDef := "" }} + {{- if .Entry }} + {{ $funcDef = "CreateWithXpath(ctx context.Context, xpath string, entry *Entry) error" }} + {{- else }} + {{ $funcDef = "CreateWithXpath(ctx context.Context, xpath string, config *Config) error" }} + {{- end }} -{{- if .Entry}} - return s.Read(ctx, loc, entry.Name, "get") -{{- else}} - return s.Read(ctx, loc, "get") -{{- end}} +func (s *Service) {{ $funcDef }} { + vn := s.client.Versioning() + specifier, _, err := Versioning(vn) + if err != nil { + return err + } + + {{- if .Entry}} + createSpec, err := specifier(entry) + {{- else}} + createSpec, err := specifier(config) + {{- end}} + if err != nil { + return err + } + + cmd := &xmlapi.Config{ + Action: "set", + Xpath: xpath, + Element: createSpec, + Target: s.client.GetTarget(), + } + + if _, _, err = s.client.Communicate(ctx, cmd, false, nil); err != nil { + return err + } + + return nil } {{- if .Imports }} -func (s *Service) importToLocations(ctx context.Context, loc Location, importLocations []ImportLocation, entryName string) error { +func (s *Service) ImportToLocations(ctx context.Context, loc Location, importLocations []ImportLocation, entryName string) error { vn := s.client.Versioning() importToLocation := func(il ImportLocation) error { @@ -186,7 +204,7 @@ func (s *Service) importToLocations(ctx context.Context, loc Location, importLoc return nil } -func (s *Service) unimportFromLocations(ctx context.Context, loc Location, importLocations []ImportLocation, values []string) error { +func (s *Service) UnimportFromLocations(ctx context.Context, loc Location, importLocations []ImportLocation, values []string) error { vn := s.client.Versioning() valuesByName := make(map[string]bool) for _, elt := range values { @@ -259,115 +277,100 @@ func (s *Service) unimportFromLocations(ctx context.Context, loc Location, impor {{- if .Entry}} func (s *Service) Read(ctx context.Context, loc Location, name, action string) (*Entry, error) { {{- if $.Spec.Params.uuid}} - return s.read(ctx, loc, name, action, true, false) + return s.read(ctx, loc, name, action, true) {{- else}} - return s.read(ctx, loc, name, action, false) + return s.read(ctx, loc, name, action) {{- end}} } {{- if $.Spec.Params.uuid}} // ReadById returns the given config object with specified ID, using the specified action ("get" or "show"). func (s *Service) ReadById(ctx context.Context, loc Location, uuid, action string) (*Entry, error) { - return s.read(ctx, loc, uuid, action, false, false) + return s.read(ctx, loc, uuid, action, false) } {{- end}} {{- else}} func (s *Service) Read(ctx context.Context, loc Location, action string) (*Config, error) { - return s.read(ctx, loc, action, false) + return s.read(ctx, loc, action) } {{- end}} -// ReadFromConfig returns the given config object from the loaded XML config. -// Requires that client.LoadPanosConfig() has been invoked. -{{- if .Entry}} - func (s *Service) ReadFromConfig(ctx context.Context, loc Location, name string) (*Entry, error) { - {{- if $.Spec.Params.uuid}} - return s.read(ctx, loc, name, "", true, true) - {{- else}} - return s.read(ctx, loc, name, "", true) - {{- end}} - } - {{- if $.Spec.Params.uuid}} - // ReadFromConfigById returns the given config object with specified ID from the loaded XML config. - // Requires that client.LoadPanosConfig() has been invoked. - func (s *Service) ReadFromConfigById(ctx context.Context, loc Location, uuid string) (*Entry, error) { - return s.read(ctx, loc, uuid, "", false, true) - } - {{- end}} -{{- else}} - func (s *Service) ReadFromConfig(ctx context.Context, loc Location) (*Config, error) { - return s.read(ctx, loc, "", true) - } -{{- end}} + {{ $funcDef := "" }} + {{- if .Entry }} + {{ $funcDef = "ReadWithXpath(ctx context.Context, xpath string, action string) (*Entry, error)" }} + {{- else }} + {{ $funcDef = "ReadWithXpath(ctx context.Context, xpath string, action string) (*Config, error)" }} + {{- end }} +func (s *Service) {{ $funcDef }} { + vn := s.client.Versioning() + _, normalizer, err := Versioning(vn) + if err != nil { + return nil, err + } + + cmd := &xmlapi.Config{ + Action: action, + Xpath: xpath, + Target: s.client.GetTarget(), + } + + if _, _, err = s.client.Communicate(ctx, cmd, true, normalizer); err != nil { + if err.Error() == "No such node" && action == "show" { + return nil, errors.ObjectNotFound() + } + return nil, err + } + + list, err := normalizer.Normalize() + if err != nil { + return nil, err + } else if len(list) != 1 { + return nil, fmt.Errorf("expected to %q 1 entry, got %d", action, len(list)) + } + + return list[0], nil +} -{{if .Entry}} + {{if .Entry}} {{- if $.Spec.Params.uuid}} - func (s *Service) read(ctx context.Context, loc Location, value, action string, byName, usePanosConfig bool) (*Entry, error) { +func (s *Service) read(ctx context.Context, loc Location, value, action string, byName bool) (*Entry, error) { if byName && value == "" { - return nil, errors.NameNotSpecifiedError - } - if !byName && value == "" { - return nil, errors.UuidNotSpecifiedError + return nil, errors.NameNotSpecifiedError } + + if !byName && value == "" { + return nil, errors.UuidNotSpecifiedError + } {{- else}} - func (s *Service) read(ctx context.Context, loc Location, value, action string, usePanosConfig bool) (*Entry, error) { +func (s *Service) read(ctx context.Context, loc Location, value, action string) (*Entry, error) { if value == "" { return nil, errors.NameNotSpecifiedError } {{- end}} -{{- else}} - func (s *Service) read(ctx context.Context, loc Location, action string, usePanosConfig bool) (*Config, error) { -{{- end}} -vn := s.client.Versioning() -_, normalizer, err := Versioning(vn) -if err != nil { -return nil, err -} + {{- else}} +func (s *Service) read(ctx context.Context, loc Location, action string) (*Config, error) { + {{- end}} + vn := s.client.Versioning() -{{- if .Entry}} - var path []string + {{- if .Entry}} + var path []string + var err error {{- if $.Spec.Params.uuid}} - if byName { - path, err = loc.XpathWithEntryName(vn, value) - } else { - path, err = loc.XpathWithUuid(vn, value) - } + if byName { + path, err = loc.XpathWithEntryName(vn, value) + } else { + path, err = loc.XpathWithUuid(vn, value) + } {{- else}} - path, err = loc.XpathWithEntryName(vn, value) + path, err = loc.XpathWithEntryName(vn, value) {{- end}} -{{- else}} - path, err := loc.Xpath(vn) -{{- end}} -if err != nil { -return nil, err -} - -if usePanosConfig { -if _, err = s.client.ReadFromConfig(ctx, path, true, normalizer); err != nil { -return nil, err -} -} else { -cmd := &xmlapi.Config{ -Action: action, -Xpath: util.AsXpath(path), -Target: s.client.GetTarget(), -} - -if _, _, err = s.client.Communicate(ctx, cmd, true, normalizer); err != nil { -if err.Error() == "No such node" && action == "show" { -return nil, errors.ObjectNotFound() -} -return nil, err -} -} - -list, err := normalizer.Normalize() -if err != nil { -return nil, err -} else if len(list) != 1 { -return nil, fmt.Errorf("expected to %q 1 entry, got %d", action, len(list)) -} + {{- else}} + path, err := loc.Xpath(vn) + {{- end}} + if err != nil { + return nil, err + } -return list[0], nil + return s.ReadWithXpath(ctx, util.AsXpath(path), action) } {{ $object := "Config" }} @@ -585,7 +588,7 @@ vn := s.client.Versioning() var err error deletes := xmlapi.NewMultiConfig(len(values)) {{- if .Imports }} - err = s.unimportFromLocations(ctx, loc, importLocations, values) + err = s.UnimportFromLocations(ctx, loc, importLocations, values) if err != nil { return err }