diff --git a/docs/data-sources/network_group_policies.md b/docs/data-sources/network_group_policies.md
index 085a212..09984f3 100644
--- a/docs/data-sources/network_group_policies.md
+++ b/docs/data-sources/network_group_policies.md
@@ -33,8 +33,16 @@ data "meraki_network_group_policies" "example" {
### Read-Only
+- `bandwidth_bandwidth_limits_limit_down` (Number)
+- `bandwidth_bandwidth_limits_limit_up` (Number)
+- `bandwidth_settings` (String)
- `bonjour_forwarding_rules` (Attributes List) (see [below for nested schema](#nestedatt--bonjour_forwarding_rules))
- `bonjour_forwarding_settings` (String)
+- `content_filtering_allowed_url_patterns_settings` (String)
+- `content_filtering_blocked_url_categories_categories` (List of String)
+- `content_filtering_blocked_url_categories_settings` (String)
+- `content_filtering_blocked_url_patterns_patterns` (List of String)
+- `content_filtering_blocked_url_patterns_settings` (String)
### Nested Schema for `bonjour_forwarding_rules`
diff --git a/docs/resources/network_group_policies.md b/docs/resources/network_group_policies.md
index c91faad..577c6f4 100644
--- a/docs/resources/network_group_policies.md
+++ b/docs/resources/network_group_policies.md
@@ -24,6 +24,14 @@ resource "meraki_network_group_policies" "example" {
vlan_id = "2"
}
]
+ bandwidth_bandwidth_limits_limit_down = 1000000
+ bandwidth_bandwidth_limits_limit_up = 1000000
+ bandwidth_settings = "custom"
+ content_filtering_allowed_url_patterns_settings = "network default"
+ content_filtering_blocked_url_categories_categories = ["meraki:contentFiltering/category/1"]
+ content_filtering_blocked_url_categories_settings = "override"
+ content_filtering_blocked_url_patterns_patterns = ["http://www.betting.com"]
+ content_filtering_blocked_url_patterns_settings = "append"
}
```
@@ -37,8 +45,16 @@ resource "meraki_network_group_policies" "example" {
### Optional
+- `bandwidth_bandwidth_limits_limit_down` (Number)
+- `bandwidth_bandwidth_limits_limit_up` (Number)
+- `bandwidth_settings` (String)
- `bonjour_forwarding_rules` (Attributes List) (see [below for nested schema](#nestedatt--bonjour_forwarding_rules))
- `bonjour_forwarding_settings` (String)
+- `content_filtering_allowed_url_patterns_settings` (String)
+- `content_filtering_blocked_url_categories_categories` (List of String)
+- `content_filtering_blocked_url_categories_settings` (String)
+- `content_filtering_blocked_url_patterns_patterns` (List of String)
+- `content_filtering_blocked_url_patterns_settings` (String)
### Read-Only
diff --git a/examples/resources/meraki_network_group_policies/resource.tf b/examples/resources/meraki_network_group_policies/resource.tf
index 290b95e..59abd94 100644
--- a/examples/resources/meraki_network_group_policies/resource.tf
+++ b/examples/resources/meraki_network_group_policies/resource.tf
@@ -9,4 +9,12 @@ resource "meraki_network_group_policies" "example" {
vlan_id = "2"
}
]
+ bandwidth_bandwidth_limits_limit_down = 1000000
+ bandwidth_bandwidth_limits_limit_up = 1000000
+ bandwidth_settings = "custom"
+ content_filtering_allowed_url_patterns_settings = "network default"
+ content_filtering_blocked_url_categories_categories = ["meraki:contentFiltering/category/1"]
+ content_filtering_blocked_url_categories_settings = "override"
+ content_filtering_blocked_url_patterns_patterns = ["http://www.betting.com"]
+ content_filtering_blocked_url_patterns_settings = "append"
}
diff --git a/gen/definitions/networks_group_policies.yaml b/gen/definitions/networks_group_policies.yaml
index e20426e..fe012d6 100644
--- a/gen/definitions/networks_group_policies.yaml
+++ b/gen/definitions/networks_group_policies.yaml
@@ -34,10 +34,45 @@ attributes:
- model_name: vlanId
type: String
example: "2"
-
-
-
-
+ - model_name: limitDown
+ data_path: [bandwidth, bandwidthLimits]
+ type: Int64
+ example: 1000000
+ - model_name: limitUp
+ data_path: [bandwidth, bandwidthLimits]
+ type: Int64
+ example: 1000000
+ - model_name: settings
+ data_path: [bandwidth]
+ type: String
+ example: custom
+ - model_name: settings
+ data_path: [contentFiltering, allowedUrlPatterns]
+ exclude_test: true
+ type: String
+ example: network default
+ - model_name: categories
+ data_path: [contentFiltering, blockedUrlCategories]
+ exclude_test: true
+ type: List
+ element_type: String
+ example: meraki:contentFiltering/category/1
+ - model_name: settings
+ data_path: [contentFiltering, blockedUrlCategories]
+ exclude_test: true
+ example: override
+ type: String
+ - model_name: patterns
+ type: List
+ data_path: [contentFiltering, blockedUrlPatterns]
+ exclude_test: true
+ element_type: String
+ example: http://www.betting.com
+ - model_name: settings
+ data_path: [contentFiltering, blockedUrlPatterns]
+ exclude_test: true
+ example: append
+ type: String
test_prerequisites: |
data "meraki_organization" "test" {
diff --git a/gen/generator.go b/gen/generator.go
index 9404c6b..defa78e 100644
--- a/gen/generator.go
+++ b/gen/generator.go
@@ -30,8 +30,8 @@ import (
"regexp"
"strings"
"text/template"
- "unicode"
+ "github.com/netascode/terraform-provider-meraki/gen/generator"
"gopkg.in/yaml.v3"
)
@@ -93,360 +93,16 @@ var templates = []t{
},
}
-type YamlConfig struct {
- Name string `yaml:"name"`
- TfName string `yaml:"tf_name"`
- RestEndpoint string `yaml:"rest_endpoint"`
- PutCreate bool `yaml:"put_create"`
- GetFromAll bool `yaml:"get_from_all"`
- NoUpdate bool `yaml:"no_update"`
- NoDelete bool `yaml:"no_delete"`
- DataSourceNameQuery bool `yaml:"data_source_name_query"`
- MinimumVersion string `yaml:"minimum_version"`
- DsDescription string `yaml:"ds_description"`
- ResDescription string `yaml:"res_description"`
- DocCategory string `yaml:"doc_category"`
- ExcludeTest bool `yaml:"exclude_test"`
- SkipMinimumTest bool `yaml:"skip_minimum_test"`
- Attributes []YamlConfigAttribute `yaml:"attributes"`
- TestTags []string `yaml:"test_tags"`
- TestPrerequisites string `yaml:"test_prerequisites"`
- IdName string `yaml:"id_name"`
-}
-
-type YamlConfigAttribute struct {
- ModelName string `yaml:"model_name"`
- TfName string `yaml:"tf_name"`
- Type string `yaml:"type"`
- ElementType string `yaml:"element_type"`
- DataPath []string `yaml:"data_path"`
- Id bool `yaml:"id"`
- ResourceId bool `yaml:"resource_id"`
- Reference bool `yaml:"reference"`
- RequiresReplace bool `yaml:"requires_replace"`
- Mandatory bool `yaml:"mandatory"`
- WriteOnly bool `yaml:"write_only"`
- WriteChangesOnly bool `yaml:"write_changes_only"`
- ExcludeTest bool `yaml:"exclude_test"`
- ExcludeExample bool `yaml:"exclude_example"`
- Description string `yaml:"description"`
- Example string `yaml:"example"`
- EnumValues []string `yaml:"enum_values"`
- MinList int64 `yaml:"min_list"`
- MaxList int64 `yaml:"max_list"`
- MinInt int64 `yaml:"min_int"`
- MaxInt int64 `yaml:"max_int"`
- MinFloat float64 `yaml:"min_float"`
- MaxFloat float64 `yaml:"max_float"`
- MapKeyExample string `yaml:"map_key_example"`
- OrderedList bool `yaml:"ordered_list"`
- StringPatterns []string `yaml:"string_patterns"`
- StringMinLength int64 `yaml:"string_min_length"`
- StringMaxLength int64 `yaml:"string_max_length"`
- DefaultValue string `yaml:"default_value"`
- Value string `yaml:"value"`
- TestValue string `yaml:"test_value"`
- MinimumTestValue string `yaml:"minimum_test_value"`
- TestTags []string `yaml:"test_tags"`
- Attributes []YamlConfigAttribute `yaml:"attributes"`
- GoTypeName string
-}
-
-// Templating helper function to convert TF name to GO name
-func ToGoName(s string) string {
- var g []string
-
- p := strings.Split(s, "_")
-
- for _, value := range p {
- g = append(g, strings.Title(value))
- }
- s = strings.Join(g, "")
- return s
-}
-
-// Templating helper function to convert string to camel case
-func CamelCase(s string) string {
- var g []string
-
- s = strings.ReplaceAll(s, "-", " ")
- p := strings.Fields(s)
-
- for _, value := range p {
- g = append(g, strings.Title(value))
- }
- return strings.Join(g, "")
-}
-
-func DromedaryCase(s string) string {
- s = ToGoName(s)
- return strings.ToLower(string(s[0])) + s[1:]
-}
-
-// Templating helper function to convert string to snake case
-func SnakeCase(s string) string {
- var g []string
-
- s = strings.ReplaceAll(s, "-", " ")
- p := strings.Fields(s)
-
- for _, value := range p {
- g = append(g, strings.ToLower(value))
- }
- return strings.Join(g, "_")
-}
-
-// Templating helper function to fail a template mid-way
-func Errorf(s string, args ...any) (struct{}, error) {
- return struct{}{}, fmt.Errorf(s, args...)
-}
-
-// Templating helper function to build a SJSON path
-func BuildPath(s []string) string {
- return strings.Join(s, ".")
-}
-
-func contains(s []string, str string) bool {
- for _, v := range s {
- if v == str {
- return true
- }
- }
- return false
-}
-
-// Templating helper function to return true if id included in attributes
-func HasId(attributes []YamlConfigAttribute) bool {
- for _, attr := range attributes {
- if attr.Id {
- return true
- }
- }
- return false
-}
-
-// Templating helper function to return true if reference included in attributes
-func HasReference(attributes []YamlConfigAttribute) bool {
- for _, attr := range attributes {
- if attr.Reference {
- return true
- }
- }
- return false
-}
-
-// Templating helper function to return true if reference included in attributes
-func HasResourceId(attributes []YamlConfigAttribute) bool {
- for _, attr := range attributes {
- if attr.ResourceId {
- return true
- }
- if len(attr.Attributes) > 0 {
- if HasResourceId(attr.Attributes) {
- return true
- }
- }
- }
- return false
-}
-
-// Templating helper function to return true if type is a list or set without nested elements
-func IsListSet(attribute YamlConfigAttribute) bool {
- if (attribute.Type == "List" || attribute.Type == "Set") && attribute.ElementType != "" {
- return true
- }
- return false
-}
-
-// Templating helper function to return true if type is a list without nested elements
-func IsList(attribute YamlConfigAttribute) bool {
- if attribute.Type == "List" && attribute.ElementType != "" {
- return true
- }
- return false
-}
-
-// Templating helper function to return true if type is a set without nested elements
-func IsSet(attribute YamlConfigAttribute) bool {
- if attribute.Type == "Set" && attribute.ElementType != "" {
- return true
- }
- return false
-}
-
-// Templating helper function to return true if type is a list or set of strings without nested elements
-func IsStringListSet(attribute YamlConfigAttribute) bool {
- if (attribute.Type == "List" || attribute.Type == "Set") && attribute.ElementType == "String" {
- return true
- }
- return false
-}
-
-// Templating helper function to return true if type is a list or set of integers without nested elements
-func IsInt64ListSet(attribute YamlConfigAttribute) bool {
- if (attribute.Type == "List" || attribute.Type == "Set") && attribute.ElementType == "Int64" {
- return true
- }
- return false
-}
-
-// Templating helper function to return true if type is a list or a map or a set, anyway with nested elements
-func IsNestedListMapSet(attribute YamlConfigAttribute) bool {
- if (attribute.Type == "List" || attribute.Type == "Map" || attribute.Type == "Set") && attribute.ElementType == "" {
- return true
- }
- return false
-}
-
-// Templating helper function to return true if type is a list or set with nested elements
-func IsNestedListSet(attribute YamlConfigAttribute) bool {
- if (attribute.Type == "List" || attribute.Type == "Set") && attribute.ElementType == "" {
- return true
- }
- return false
-}
-
-// Templating helper function to return true if type is a list with nested elements
-func IsNestedList(attribute YamlConfigAttribute) bool {
- if attribute.Type == "List" && attribute.ElementType == "" {
- return true
- }
- return false
-}
-
-// Templating helper function to return true if type is a map with nested elements
-func IsNestedMap(attribute YamlConfigAttribute) bool {
- if attribute.Type == "Map" && attribute.ElementType == "" {
- return true
- }
- return false
-}
-
-// Templating helper function to return true if type is a set with nested elements
-func IsNestedSet(attribute YamlConfigAttribute) bool {
- if attribute.Type == "Set" && attribute.ElementType == "" {
- return true
- }
- return false
-}
-
-// Templating helper function to return number of import parts
-func ImportParts(attributes []YamlConfigAttribute) int {
- parts := 1
- for _, attr := range attributes {
- if attr.Reference {
- parts += 1
- } else if attr.Id {
- parts += 1
- }
- }
- return parts
-}
-
-// Templating helper function to subtract one number from another
-func Subtract(a, b int) int {
- return a - b
-}
-
-// Map of templating functions
-var functions = template.FuncMap{
- "toGoName": ToGoName,
- "dromedaryCase": DromedaryCase,
- "camelCase": CamelCase,
- "snakeCase": SnakeCase,
- "sprintf": fmt.Sprintf,
- "errorf": Errorf,
- "toLower": strings.ToLower,
- "path": BuildPath,
- "hasId": HasId,
- "hasReference": HasReference,
- "hasResourceId": HasResourceId,
- "isListSet": IsListSet,
- "isList": IsList,
- "isSet": IsSet,
- "isStringListSet": IsStringListSet,
- "isInt64ListSet": IsInt64ListSet,
- "isNestedListMapSet": IsNestedListMapSet,
- "isNestedListSet": IsNestedListSet,
- "isNestedList": IsNestedList,
- "isNestedMap": IsNestedMap,
- "isNestedSet": IsNestedSet,
- "importParts": ImportParts,
- "subtract": Subtract,
-}
-
-func (attr *YamlConfigAttribute) init(parentGoTypeName string) error {
- // Augument
- if attr.TfName == "" {
- var words []string
- fullString := ""
- for _, s := range attr.DataPath {
- fullString += strings.ToUpper(string(s[0])) + s[1:]
- }
- fullString += strings.ToUpper(string(attr.ModelName[0])) + attr.ModelName[1:]
- l := 0
- for s := fullString; s != ""; s = s[l:] {
- l = strings.IndexFunc(s[1:], unicode.IsUpper) + 1
- if l <= 0 {
- l = len(s)
- }
- words = append(words, strings.ToLower(s[:l]))
- }
- attr.TfName = strings.Join(words, "_")
- }
-
- attr.GoTypeName = parentGoTypeName + ToGoName(attr.TfName)
-
- // Validate
- if len(attr.Attributes) > 0 && attr.Type != "List" && attr.Type != "Map" && attr.Type != "Set" {
- return fmt.Errorf("%q has type %q which cannot have `attributes`: instead use type List, Map, Set",
- attr.TfName, attr.Type)
- }
-
- if len(attr.Attributes) > 0 && attr.ElementType != "" {
- return fmt.Errorf("%q: either `attributes` or `element_type` can be specified, but not both", attr.TfName)
- }
-
- if attr.Type == "Map" && attr.ElementType != "" {
- return fmt.Errorf("%q: the `element_type` is not yet implemented for type Map", attr.TfName)
- }
-
- if attr.OrderedList {
- if attr.Type != "List" {
- return fmt.Errorf("%q has type %q which cannot use `ordered_list`: instead use type List",
- attr.TfName, attr.Type)
- }
- if HasId(attr.Attributes) {
- return fmt.Errorf("%q: the `ordered_list: true` conflicts with sub-attributes having `id: true`, as it treats list index ([i]) as the only unique id",
- attr.TfName)
- }
- }
-
- if attr.Type == "Map" && HasId(attr.Attributes) {
- return fmt.Errorf("Map %q cannot contain sub-attributes with `id: true`, as it treats map key ([k]) as the only unique id",
- attr.TfName)
- }
-
- // Recurse
- for i := range attr.Attributes {
- if err := attr.Attributes[i].init(attr.GoTypeName); err != nil {
- return err
- }
- }
-
- return nil
-}
-
-func NewYamlConfig(bytes []byte) (YamlConfig, error) {
- var config YamlConfig
+func NewYamlConfig(bytes []byte) (generator.YamlConfig, error) {
+ var config generator.YamlConfig
if err := yaml.Unmarshal(bytes, &config); err != nil {
return config, err
}
for i := range config.Attributes {
- if err := config.Attributes[i].init(CamelCase(config.Name)); err != nil {
- return YamlConfig{}, err
+ if err := config.Attributes[i].Init(generator.CamelCase(config.Name)); err != nil {
+ return generator.YamlConfig{}, err
}
}
if config.DsDescription == "" {
@@ -507,7 +163,7 @@ func renderTemplate(templatePath, outputPath string, config interface{}) {
temp = temp + scanner.Text() + "\n"
}
- template, err := template.New(path.Base(templatePath)).Funcs(functions).Parse(temp)
+ template, err := template.New(path.Base(templatePath)).Funcs(generator.Functions).Parse(temp)
if err != nil {
log.Fatalf("Error parsing template: %v", err)
}
@@ -558,7 +214,7 @@ func renderTemplate(templatePath, outputPath string, config interface{}) {
func main() {
// Load configs
- var configs []YamlConfig
+ var configs []generator.YamlConfig
files, _ := os.ReadDir(definitionsPath)
for _, filename := range files {
@@ -579,7 +235,7 @@ func main() {
for i := range configs {
// Iterate over templates and render files
for _, t := range templates {
- renderTemplate(t.path, t.prefix+SnakeCase(configs[i].Name)+t.suffix, configs[i])
+ renderTemplate(t.path, t.prefix+generator.SnakeCase(configs[i].Name)+t.suffix, configs[i])
}
providerConfig = append(providerConfig, configs[i].Name)
}
diff --git a/gen/generator/model.go b/gen/generator/model.go
new file mode 100644
index 0000000..59c7f1b
--- /dev/null
+++ b/gen/generator/model.go
@@ -0,0 +1,128 @@
+package generator
+
+import (
+ "fmt"
+ "strings"
+ "unicode"
+)
+
+type YamlConfig struct {
+ Name string `yaml:"name"`
+ TfName string `yaml:"tf_name"`
+ RestEndpoint string `yaml:"rest_endpoint"`
+ PutCreate bool `yaml:"put_create"`
+ GetFromAll bool `yaml:"get_from_all"`
+ NoUpdate bool `yaml:"no_update"`
+ NoDelete bool `yaml:"no_delete"`
+ DataSourceNameQuery bool `yaml:"data_source_name_query"`
+ MinimumVersion string `yaml:"minimum_version"`
+ DsDescription string `yaml:"ds_description"`
+ ResDescription string `yaml:"res_description"`
+ DocCategory string `yaml:"doc_category"`
+ ExcludeTest bool `yaml:"exclude_test"`
+ SkipMinimumTest bool `yaml:"skip_minimum_test"`
+ Attributes []YamlConfigAttribute `yaml:"attributes"`
+ TestTags []string `yaml:"test_tags"`
+ TestPrerequisites string `yaml:"test_prerequisites"`
+ IdName string `yaml:"id_name"`
+}
+
+type YamlConfigAttribute struct {
+ ModelName string `yaml:"model_name"`
+ TfName string `yaml:"tf_name"`
+ Type string `yaml:"type"`
+ ElementType string `yaml:"element_type"`
+ DataPath []string `yaml:"data_path"`
+ Id bool `yaml:"id"`
+ ResourceId bool `yaml:"resource_id"`
+ Reference bool `yaml:"reference"`
+ RequiresReplace bool `yaml:"requires_replace"`
+ Mandatory bool `yaml:"mandatory"`
+ WriteOnly bool `yaml:"write_only"`
+ WriteChangesOnly bool `yaml:"write_changes_only"`
+ ExcludeTest bool `yaml:"exclude_test"`
+ ExcludeExample bool `yaml:"exclude_example"`
+ Description string `yaml:"description"`
+ Example string `yaml:"example"`
+ EnumValues []string `yaml:"enum_values"`
+ MinList int64 `yaml:"min_list"`
+ MaxList int64 `yaml:"max_list"`
+ MinInt int64 `yaml:"min_int"`
+ MaxInt int64 `yaml:"max_int"`
+ MinFloat float64 `yaml:"min_float"`
+ MaxFloat float64 `yaml:"max_float"`
+ MapKeyExample string `yaml:"map_key_example"`
+ OrderedList bool `yaml:"ordered_list"`
+ StringPatterns []string `yaml:"string_patterns"`
+ StringMinLength int64 `yaml:"string_min_length"`
+ StringMaxLength int64 `yaml:"string_max_length"`
+ DefaultValue string `yaml:"default_value"`
+ Value string `yaml:"value"`
+ TestValue string `yaml:"test_value"`
+ MinimumTestValue string `yaml:"minimum_test_value"`
+ TestTags []string `yaml:"test_tags"`
+ Attributes []YamlConfigAttribute `yaml:"attributes"`
+ GoTypeName string
+}
+
+func (attr *YamlConfigAttribute) Init(parentGoTypeName string) error {
+ // Augument
+ if attr.TfName == "" {
+ var words []string
+ fullString := ""
+ for _, s := range attr.DataPath {
+ fullString += strings.ToUpper(string(s[0])) + s[1:]
+ }
+ fullString += strings.ToUpper(string(attr.ModelName[0])) + attr.ModelName[1:]
+ l := 0
+ for s := fullString; s != ""; s = s[l:] {
+ l = strings.IndexFunc(s[1:], unicode.IsUpper) + 1
+ if l <= 0 {
+ l = len(s)
+ }
+ words = append(words, strings.ToLower(s[:l]))
+ }
+ attr.TfName = strings.Join(words, "_")
+ }
+
+ attr.GoTypeName = parentGoTypeName + ToGoName(attr.TfName)
+
+ // Validate
+ if len(attr.Attributes) > 0 && attr.Type != "List" && attr.Type != "Map" && attr.Type != "Set" {
+ return fmt.Errorf("%q has type %q which cannot have `attributes`: instead use type List, Map, Set",
+ attr.TfName, attr.Type)
+ }
+
+ if len(attr.Attributes) > 0 && attr.ElementType != "" {
+ return fmt.Errorf("%q: either `attributes` or `element_type` can be specified, but not both", attr.TfName)
+ }
+
+ if attr.Type == "Map" && attr.ElementType != "" {
+ return fmt.Errorf("%q: the `element_type` is not yet implemented for type Map", attr.TfName)
+ }
+
+ if attr.OrderedList {
+ if attr.Type != "List" {
+ return fmt.Errorf("%q has type %q which cannot use `ordered_list`: instead use type List",
+ attr.TfName, attr.Type)
+ }
+ if HasId(attr.Attributes) {
+ return fmt.Errorf("%q: the `ordered_list: true` conflicts with sub-attributes having `id: true`, as it treats list index ([i]) as the only unique id",
+ attr.TfName)
+ }
+ }
+
+ if attr.Type == "Map" && HasId(attr.Attributes) {
+ return fmt.Errorf("Map %q cannot contain sub-attributes with `id: true`, as it treats map key ([k]) as the only unique id",
+ attr.TfName)
+ }
+
+ // Recurse
+ for i := range attr.Attributes {
+ if err := attr.Attributes[i].Init(attr.GoTypeName); err != nil {
+ return err
+ }
+ }
+
+ return nil
+}
diff --git a/gen/generator/template_functions.go b/gen/generator/template_functions.go
new file mode 100644
index 0000000..a5aa560
--- /dev/null
+++ b/gen/generator/template_functions.go
@@ -0,0 +1,230 @@
+package generator
+
+import (
+ "fmt"
+ "strings"
+ "text/template"
+)
+
+// Templating helper function to convert TF name to GO name
+func ToGoName(s string) string {
+ var g []string
+
+ p := strings.Split(s, "_")
+
+ for _, value := range p {
+ g = append(g, strings.Title(value))
+ }
+ s = strings.Join(g, "")
+ return s
+}
+
+// Templating helper function to convert string to camel case
+func CamelCase(s string) string {
+ var g []string
+
+ s = strings.ReplaceAll(s, "-", " ")
+ p := strings.Fields(s)
+
+ for _, value := range p {
+ g = append(g, strings.Title(value))
+ }
+ return strings.Join(g, "")
+}
+
+func DromedaryCase(s string) string {
+ s = ToGoName(s)
+ return strings.ToLower(string(s[0])) + s[1:]
+}
+
+// Templating helper function to convert string to snake case
+func SnakeCase(s string) string {
+ var g []string
+
+ s = strings.ReplaceAll(s, "-", " ")
+ p := strings.Fields(s)
+
+ for _, value := range p {
+ g = append(g, strings.ToLower(value))
+ }
+ return strings.Join(g, "_")
+}
+
+// Templating helper function to fail a template mid-way
+func Errorf(s string, args ...any) (struct{}, error) {
+ return struct{}{}, fmt.Errorf(s, args...)
+}
+
+// Templating helper function to build a SJSON path
+func BuildPath(s []string) string {
+ return strings.Join(s, ".")
+}
+
+func contains(s []string, str string) bool {
+ for _, v := range s {
+ if v == str {
+ return true
+ }
+ }
+ return false
+}
+
+// Templating helper function to return true if id included in attributes
+func HasId(attributes []YamlConfigAttribute) bool {
+ for _, attr := range attributes {
+ if attr.Id {
+ return true
+ }
+ }
+ return false
+}
+
+// Templating helper function to return true if reference included in attributes
+func HasReference(attributes []YamlConfigAttribute) bool {
+ for _, attr := range attributes {
+ if attr.Reference {
+ return true
+ }
+ }
+ return false
+}
+
+// Templating helper function to return true if reference included in attributes
+func HasResourceId(attributes []YamlConfigAttribute) bool {
+ for _, attr := range attributes {
+ if attr.ResourceId {
+ return true
+ }
+ if len(attr.Attributes) > 0 {
+ if HasResourceId(attr.Attributes) {
+ return true
+ }
+ }
+ }
+ return false
+}
+
+// Templating helper function to return true if type is a list or set without nested elements
+func IsListSet(attribute YamlConfigAttribute) bool {
+ if (attribute.Type == "List" || attribute.Type == "Set") && attribute.ElementType != "" {
+ return true
+ }
+ return false
+}
+
+// Templating helper function to return true if type is a list without nested elements
+func IsList(attribute YamlConfigAttribute) bool {
+ if attribute.Type == "List" && attribute.ElementType != "" {
+ return true
+ }
+ return false
+}
+
+// Templating helper function to return true if type is a set without nested elements
+func IsSet(attribute YamlConfigAttribute) bool {
+ if attribute.Type == "Set" && attribute.ElementType != "" {
+ return true
+ }
+ return false
+}
+
+// Templating helper function to return true if type is a list or set of strings without nested elements
+func IsStringListSet(attribute YamlConfigAttribute) bool {
+ if (attribute.Type == "List" || attribute.Type == "Set") && attribute.ElementType == "String" {
+ return true
+ }
+ return false
+}
+
+// Templating helper function to return true if type is a list or set of integers without nested elements
+func IsInt64ListSet(attribute YamlConfigAttribute) bool {
+ if (attribute.Type == "List" || attribute.Type == "Set") && attribute.ElementType == "Int64" {
+ return true
+ }
+ return false
+}
+
+// Templating helper function to return true if type is a list or a map or a set, anyway with nested elements
+func IsNestedListMapSet(attribute YamlConfigAttribute) bool {
+ if (attribute.Type == "List" || attribute.Type == "Map" || attribute.Type == "Set") && attribute.ElementType == "" {
+ return true
+ }
+ return false
+}
+
+// Templating helper function to return true if type is a list or set with nested elements
+func IsNestedListSet(attribute YamlConfigAttribute) bool {
+ if (attribute.Type == "List" || attribute.Type == "Set") && attribute.ElementType == "" {
+ return true
+ }
+ return false
+}
+
+// Templating helper function to return true if type is a list with nested elements
+func IsNestedList(attribute YamlConfigAttribute) bool {
+ if attribute.Type == "List" && attribute.ElementType == "" {
+ return true
+ }
+ return false
+}
+
+// Templating helper function to return true if type is a map with nested elements
+func IsNestedMap(attribute YamlConfigAttribute) bool {
+ if attribute.Type == "Map" && attribute.ElementType == "" {
+ return true
+ }
+ return false
+}
+
+// Templating helper function to return true if type is a set with nested elements
+func IsNestedSet(attribute YamlConfigAttribute) bool {
+ if attribute.Type == "Set" && attribute.ElementType == "" {
+ return true
+ }
+ return false
+}
+
+// Templating helper function to return number of import parts
+func ImportParts(attributes []YamlConfigAttribute) int {
+ parts := 1
+ for _, attr := range attributes {
+ if attr.Reference {
+ parts += 1
+ } else if attr.Id {
+ parts += 1
+ }
+ }
+ return parts
+}
+
+// Templating helper function to subtract one number from another
+func Subtract(a, b int) int {
+ return a - b
+}
+
+// Map of templating functions
+var Functions = template.FuncMap{
+ "toGoName": ToGoName,
+ "dromedaryCase": DromedaryCase,
+ "camelCase": CamelCase,
+ "snakeCase": SnakeCase,
+ "sprintf": fmt.Sprintf,
+ "errorf": Errorf,
+ "toLower": strings.ToLower,
+ "path": BuildPath,
+ "hasId": HasId,
+ "hasReference": HasReference,
+ "hasResourceId": HasResourceId,
+ "isListSet": IsListSet,
+ "isList": IsList,
+ "isSet": IsSet,
+ "isStringListSet": IsStringListSet,
+ "isInt64ListSet": IsInt64ListSet,
+ "isNestedListMapSet": IsNestedListMapSet,
+ "isNestedListSet": IsNestedListSet,
+ "isNestedList": IsNestedList,
+ "isNestedMap": IsNestedMap,
+ "isNestedSet": IsNestedSet,
+ "importParts": ImportParts,
+ "subtract": Subtract,
+}
diff --git a/internal/provider/data_source_meraki_network_group_policies.go b/internal/provider/data_source_meraki_network_group_policies.go
index 124caff..40e5302 100644
--- a/internal/provider/data_source_meraki_network_group_policies.go
+++ b/internal/provider/data_source_meraki_network_group_policies.go
@@ -100,6 +100,40 @@ func (d *NetworkGroupPoliciesDataSource) Schema(ctx context.Context, req datasou
},
},
},
+ "bandwidth_bandwidth_limits_limit_down": schema.Int64Attribute{
+ MarkdownDescription: "",
+ Computed: true,
+ },
+ "bandwidth_bandwidth_limits_limit_up": schema.Int64Attribute{
+ MarkdownDescription: "",
+ Computed: true,
+ },
+ "bandwidth_settings": schema.StringAttribute{
+ MarkdownDescription: "",
+ Computed: true,
+ },
+ "content_filtering_allowed_url_patterns_settings": schema.StringAttribute{
+ MarkdownDescription: "",
+ Computed: true,
+ },
+ "content_filtering_blocked_url_categories_categories": schema.ListAttribute{
+ MarkdownDescription: "",
+ ElementType: types.StringType,
+ Computed: true,
+ },
+ "content_filtering_blocked_url_categories_settings": schema.StringAttribute{
+ MarkdownDescription: "",
+ Computed: true,
+ },
+ "content_filtering_blocked_url_patterns_patterns": schema.ListAttribute{
+ MarkdownDescription: "",
+ ElementType: types.StringType,
+ Computed: true,
+ },
+ "content_filtering_blocked_url_patterns_settings": schema.StringAttribute{
+ MarkdownDescription: "",
+ Computed: true,
+ },
},
}
}
diff --git a/internal/provider/data_source_meraki_network_group_policies_test.go b/internal/provider/data_source_meraki_network_group_policies_test.go
index be20ce6..144d552 100644
--- a/internal/provider/data_source_meraki_network_group_policies_test.go
+++ b/internal/provider/data_source_meraki_network_group_policies_test.go
@@ -35,6 +35,9 @@ func TestAccDataSourceMerakiNetworkGroupPolicies(t *testing.T) {
checks = append(checks, resource.TestCheckResourceAttr("data.meraki_network_group_policies.test", "bonjour_forwarding_rules.0.description", "a simple bonjour rule"))
checks = append(checks, resource.TestCheckResourceAttr("data.meraki_network_group_policies.test", "bonjour_forwarding_rules.0.services.0", "All Services"))
checks = append(checks, resource.TestCheckResourceAttr("data.meraki_network_group_policies.test", "bonjour_forwarding_rules.0.vlan_id", "2"))
+ checks = append(checks, resource.TestCheckResourceAttr("data.meraki_network_group_policies.test", "bandwidth_bandwidth_limits_limit_down", "1000000"))
+ checks = append(checks, resource.TestCheckResourceAttr("data.meraki_network_group_policies.test", "bandwidth_bandwidth_limits_limit_up", "1000000"))
+ checks = append(checks, resource.TestCheckResourceAttr("data.meraki_network_group_policies.test", "bandwidth_settings", "custom"))
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
ProtoV6ProviderFactories: testAccProtoV6ProviderFactories,
@@ -81,6 +84,9 @@ func testAccDataSourceMerakiNetworkGroupPoliciesConfig() string {
config += ` services = ["All Services"]` + "\n"
config += ` vlan_id = "2"` + "\n"
config += ` }]` + "\n"
+ config += ` bandwidth_bandwidth_limits_limit_down = 1000000` + "\n"
+ config += ` bandwidth_bandwidth_limits_limit_up = 1000000` + "\n"
+ config += ` bandwidth_settings = "custom"` + "\n"
config += `}` + "\n"
config += `
@@ -102,6 +108,9 @@ func testAccNamedDataSourceMerakiNetworkGroupPoliciesConfig() string {
config += ` services = ["All Services"]` + "\n"
config += ` vlan_id = "2"` + "\n"
config += ` }]` + "\n"
+ config += ` bandwidth_bandwidth_limits_limit_down = 1000000` + "\n"
+ config += ` bandwidth_bandwidth_limits_limit_up = 1000000` + "\n"
+ config += ` bandwidth_settings = "custom"` + "\n"
config += `}` + "\n"
config += `
diff --git a/internal/provider/model_meraki_network_group_policies.go b/internal/provider/model_meraki_network_group_policies.go
index 730119b..6078580 100644
--- a/internal/provider/model_meraki_network_group_policies.go
+++ b/internal/provider/model_meraki_network_group_policies.go
@@ -36,11 +36,19 @@ import (
// Section below is generated&owned by "gen/generator.go". //template:begin types
type NetworkGroupPolicies struct {
- GroupPolicyId types.String `tfsdk:"group_policy_id"`
- NetworkId types.String `tfsdk:"network_id"`
- Name types.String `tfsdk:"name"`
- BonjourForwardingSettings types.String `tfsdk:"bonjour_forwarding_settings"`
- BonjourForwardingRules []NetworkGroupPoliciesBonjourForwardingRules `tfsdk:"bonjour_forwarding_rules"`
+ GroupPolicyId types.String `tfsdk:"group_policy_id"`
+ NetworkId types.String `tfsdk:"network_id"`
+ Name types.String `tfsdk:"name"`
+ BonjourForwardingSettings types.String `tfsdk:"bonjour_forwarding_settings"`
+ BonjourForwardingRules []NetworkGroupPoliciesBonjourForwardingRules `tfsdk:"bonjour_forwarding_rules"`
+ BandwidthBandwidthLimitsLimitDown types.Int64 `tfsdk:"bandwidth_bandwidth_limits_limit_down"`
+ BandwidthBandwidthLimitsLimitUp types.Int64 `tfsdk:"bandwidth_bandwidth_limits_limit_up"`
+ BandwidthSettings types.String `tfsdk:"bandwidth_settings"`
+ ContentFilteringAllowedUrlPatternsSettings types.String `tfsdk:"content_filtering_allowed_url_patterns_settings"`
+ ContentFilteringBlockedUrlCategoriesCategories types.List `tfsdk:"content_filtering_blocked_url_categories_categories"`
+ ContentFilteringBlockedUrlCategoriesSettings types.String `tfsdk:"content_filtering_blocked_url_categories_settings"`
+ ContentFilteringBlockedUrlPatternsPatterns types.List `tfsdk:"content_filtering_blocked_url_patterns_patterns"`
+ ContentFilteringBlockedUrlPatternsSettings types.String `tfsdk:"content_filtering_blocked_url_patterns_settings"`
}
type NetworkGroupPoliciesBonjourForwardingRules struct {
@@ -90,6 +98,34 @@ func (data NetworkGroupPolicies) toBody(ctx context.Context, state NetworkGroupP
body, _ = sjson.SetRaw(body, "bonjourForwarding.rules.-1", itemBody)
}
}
+ if !data.BandwidthBandwidthLimitsLimitDown.IsNull() {
+ body, _ = sjson.Set(body, "bandwidth.bandwidthLimits.limitDown", data.BandwidthBandwidthLimitsLimitDown.ValueInt64())
+ }
+ if !data.BandwidthBandwidthLimitsLimitUp.IsNull() {
+ body, _ = sjson.Set(body, "bandwidth.bandwidthLimits.limitUp", data.BandwidthBandwidthLimitsLimitUp.ValueInt64())
+ }
+ if !data.BandwidthSettings.IsNull() {
+ body, _ = sjson.Set(body, "bandwidth.settings", data.BandwidthSettings.ValueString())
+ }
+ if !data.ContentFilteringAllowedUrlPatternsSettings.IsNull() {
+ body, _ = sjson.Set(body, "contentFiltering.allowedUrlPatterns.settings", data.ContentFilteringAllowedUrlPatternsSettings.ValueString())
+ }
+ if !data.ContentFilteringBlockedUrlCategoriesCategories.IsNull() {
+ var values []string
+ data.ContentFilteringBlockedUrlCategoriesCategories.ElementsAs(ctx, &values, false)
+ body, _ = sjson.Set(body, "contentFiltering.blockedUrlCategories.categories", values)
+ }
+ if !data.ContentFilteringBlockedUrlCategoriesSettings.IsNull() {
+ body, _ = sjson.Set(body, "contentFiltering.blockedUrlCategories.settings", data.ContentFilteringBlockedUrlCategoriesSettings.ValueString())
+ }
+ if !data.ContentFilteringBlockedUrlPatternsPatterns.IsNull() {
+ var values []string
+ data.ContentFilteringBlockedUrlPatternsPatterns.ElementsAs(ctx, &values, false)
+ body, _ = sjson.Set(body, "contentFiltering.blockedUrlPatterns.patterns", values)
+ }
+ if !data.ContentFilteringBlockedUrlPatternsSettings.IsNull() {
+ body, _ = sjson.Set(body, "contentFiltering.blockedUrlPatterns.settings", data.ContentFilteringBlockedUrlPatternsSettings.ValueString())
+ }
return body
}
@@ -132,6 +168,46 @@ func (data *NetworkGroupPolicies) fromBody(ctx context.Context, res gjson.Result
return true
})
}
+ if value := res.Get("bandwidth.bandwidthLimits.limitDown"); value.Exists() {
+ data.BandwidthBandwidthLimitsLimitDown = types.Int64Value(value.Int())
+ } else {
+ data.BandwidthBandwidthLimitsLimitDown = types.Int64Null()
+ }
+ if value := res.Get("bandwidth.bandwidthLimits.limitUp"); value.Exists() {
+ data.BandwidthBandwidthLimitsLimitUp = types.Int64Value(value.Int())
+ } else {
+ data.BandwidthBandwidthLimitsLimitUp = types.Int64Null()
+ }
+ if value := res.Get("bandwidth.settings"); value.Exists() {
+ data.BandwidthSettings = types.StringValue(value.String())
+ } else {
+ data.BandwidthSettings = types.StringNull()
+ }
+ if value := res.Get("contentFiltering.allowedUrlPatterns.settings"); value.Exists() {
+ data.ContentFilteringAllowedUrlPatternsSettings = types.StringValue(value.String())
+ } else {
+ data.ContentFilteringAllowedUrlPatternsSettings = types.StringNull()
+ }
+ if value := res.Get("contentFiltering.blockedUrlCategories.categories"); value.Exists() {
+ data.ContentFilteringBlockedUrlCategoriesCategories = helpers.GetStringList(value.Array())
+ } else {
+ data.ContentFilteringBlockedUrlCategoriesCategories = types.ListNull(types.StringType)
+ }
+ if value := res.Get("contentFiltering.blockedUrlCategories.settings"); value.Exists() {
+ data.ContentFilteringBlockedUrlCategoriesSettings = types.StringValue(value.String())
+ } else {
+ data.ContentFilteringBlockedUrlCategoriesSettings = types.StringNull()
+ }
+ if value := res.Get("contentFiltering.blockedUrlPatterns.patterns"); value.Exists() {
+ data.ContentFilteringBlockedUrlPatternsPatterns = helpers.GetStringList(value.Array())
+ } else {
+ data.ContentFilteringBlockedUrlPatternsPatterns = types.ListNull(types.StringType)
+ }
+ if value := res.Get("contentFiltering.blockedUrlPatterns.settings"); value.Exists() {
+ data.ContentFilteringBlockedUrlPatternsSettings = types.StringValue(value.String())
+ } else {
+ data.ContentFilteringBlockedUrlPatternsSettings = types.StringNull()
+ }
}
// End of section. //template:end fromBody
@@ -206,6 +282,46 @@ func (data *NetworkGroupPolicies) fromBodyPartial(ctx context.Context, res gjson
}
(*parent).BonjourForwardingRules[i] = data
}
+ if value := res.Get("bandwidth.bandwidthLimits.limitDown"); value.Exists() && !data.BandwidthBandwidthLimitsLimitDown.IsNull() {
+ data.BandwidthBandwidthLimitsLimitDown = types.Int64Value(value.Int())
+ } else {
+ data.BandwidthBandwidthLimitsLimitDown = types.Int64Null()
+ }
+ if value := res.Get("bandwidth.bandwidthLimits.limitUp"); value.Exists() && !data.BandwidthBandwidthLimitsLimitUp.IsNull() {
+ data.BandwidthBandwidthLimitsLimitUp = types.Int64Value(value.Int())
+ } else {
+ data.BandwidthBandwidthLimitsLimitUp = types.Int64Null()
+ }
+ if value := res.Get("bandwidth.settings"); value.Exists() && !data.BandwidthSettings.IsNull() {
+ data.BandwidthSettings = types.StringValue(value.String())
+ } else {
+ data.BandwidthSettings = types.StringNull()
+ }
+ if value := res.Get("contentFiltering.allowedUrlPatterns.settings"); value.Exists() && !data.ContentFilteringAllowedUrlPatternsSettings.IsNull() {
+ data.ContentFilteringAllowedUrlPatternsSettings = types.StringValue(value.String())
+ } else {
+ data.ContentFilteringAllowedUrlPatternsSettings = types.StringNull()
+ }
+ if value := res.Get("contentFiltering.blockedUrlCategories.categories"); value.Exists() && !data.ContentFilteringBlockedUrlCategoriesCategories.IsNull() {
+ data.ContentFilteringBlockedUrlCategoriesCategories = helpers.GetStringList(value.Array())
+ } else {
+ data.ContentFilteringBlockedUrlCategoriesCategories = types.ListNull(types.StringType)
+ }
+ if value := res.Get("contentFiltering.blockedUrlCategories.settings"); value.Exists() && !data.ContentFilteringBlockedUrlCategoriesSettings.IsNull() {
+ data.ContentFilteringBlockedUrlCategoriesSettings = types.StringValue(value.String())
+ } else {
+ data.ContentFilteringBlockedUrlCategoriesSettings = types.StringNull()
+ }
+ if value := res.Get("contentFiltering.blockedUrlPatterns.patterns"); value.Exists() && !data.ContentFilteringBlockedUrlPatternsPatterns.IsNull() {
+ data.ContentFilteringBlockedUrlPatternsPatterns = helpers.GetStringList(value.Array())
+ } else {
+ data.ContentFilteringBlockedUrlPatternsPatterns = types.ListNull(types.StringType)
+ }
+ if value := res.Get("contentFiltering.blockedUrlPatterns.settings"); value.Exists() && !data.ContentFilteringBlockedUrlPatternsSettings.IsNull() {
+ data.ContentFilteringBlockedUrlPatternsSettings = types.StringValue(value.String())
+ } else {
+ data.ContentFilteringBlockedUrlPatternsSettings = types.StringNull()
+ }
}
// End of section. //template:end fromBodyPartial
diff --git a/internal/provider/resource_meraki_network_group_policies.go b/internal/provider/resource_meraki_network_group_policies.go
index 11db57f..172d9b1 100644
--- a/internal/provider/resource_meraki_network_group_policies.go
+++ b/internal/provider/resource_meraki_network_group_policies.go
@@ -106,6 +106,40 @@ func (r *NetworkGroupPoliciesResource) Schema(ctx context.Context, req resource.
},
},
},
+ "bandwidth_bandwidth_limits_limit_down": schema.Int64Attribute{
+ MarkdownDescription: helpers.NewAttributeDescription("").String,
+ Optional: true,
+ },
+ "bandwidth_bandwidth_limits_limit_up": schema.Int64Attribute{
+ MarkdownDescription: helpers.NewAttributeDescription("").String,
+ Optional: true,
+ },
+ "bandwidth_settings": schema.StringAttribute{
+ MarkdownDescription: helpers.NewAttributeDescription("").String,
+ Optional: true,
+ },
+ "content_filtering_allowed_url_patterns_settings": schema.StringAttribute{
+ MarkdownDescription: helpers.NewAttributeDescription("").String,
+ Optional: true,
+ },
+ "content_filtering_blocked_url_categories_categories": schema.ListAttribute{
+ MarkdownDescription: helpers.NewAttributeDescription("").String,
+ ElementType: types.StringType,
+ Optional: true,
+ },
+ "content_filtering_blocked_url_categories_settings": schema.StringAttribute{
+ MarkdownDescription: helpers.NewAttributeDescription("").String,
+ Optional: true,
+ },
+ "content_filtering_blocked_url_patterns_patterns": schema.ListAttribute{
+ MarkdownDescription: helpers.NewAttributeDescription("").String,
+ ElementType: types.StringType,
+ Optional: true,
+ },
+ "content_filtering_blocked_url_patterns_settings": schema.StringAttribute{
+ MarkdownDescription: helpers.NewAttributeDescription("").String,
+ Optional: true,
+ },
},
}
}
diff --git a/internal/provider/resource_meraki_network_group_policies_test.go b/internal/provider/resource_meraki_network_group_policies_test.go
index 11c83b1..dc77c11 100644
--- a/internal/provider/resource_meraki_network_group_policies_test.go
+++ b/internal/provider/resource_meraki_network_group_policies_test.go
@@ -36,6 +36,9 @@ func TestAccMerakiNetworkGroupPolicies(t *testing.T) {
checks = append(checks, resource.TestCheckResourceAttr("meraki_network_group_policies.test", "bonjour_forwarding_rules.0.description", "a simple bonjour rule"))
checks = append(checks, resource.TestCheckResourceAttr("meraki_network_group_policies.test", "bonjour_forwarding_rules.0.services.0", "All Services"))
checks = append(checks, resource.TestCheckResourceAttr("meraki_network_group_policies.test", "bonjour_forwarding_rules.0.vlan_id", "2"))
+ checks = append(checks, resource.TestCheckResourceAttr("meraki_network_group_policies.test", "bandwidth_bandwidth_limits_limit_down", "1000000"))
+ checks = append(checks, resource.TestCheckResourceAttr("meraki_network_group_policies.test", "bandwidth_bandwidth_limits_limit_up", "1000000"))
+ checks = append(checks, resource.TestCheckResourceAttr("meraki_network_group_policies.test", "bandwidth_settings", "custom"))
var steps []resource.TestStep
if os.Getenv("SKIP_MINIMUM_TEST") == "" {
@@ -97,6 +100,9 @@ func testAccMerakiNetworkGroupPoliciesConfig_all() string {
config += ` services = ["All Services"]` + "\n"
config += ` vlan_id = "2"` + "\n"
config += ` }]` + "\n"
+ config += ` bandwidth_bandwidth_limits_limit_down = 1000000` + "\n"
+ config += ` bandwidth_bandwidth_limits_limit_up = 1000000` + "\n"
+ config += ` bandwidth_settings = "custom"` + "\n"
config += `}` + "\n"
return config
}
diff --git a/openapiconverter/main.go b/openapiconverter/main.go
new file mode 100644
index 0000000..99bd0d6
--- /dev/null
+++ b/openapiconverter/main.go
@@ -0,0 +1,104 @@
+package main
+
+import (
+ "encoding/json"
+ "fmt"
+ "os"
+ "strings"
+
+ "gopkg.in/yaml.v2"
+)
+
+const usage = `
+Usage: openapi-schema-parser
+
+Arguments:
+ openapi_spec Path to the file containing the OpenAPI specification (YAML or JSON)
+ schema_path Path to the schema within the OpenAPI specification file, using spaces as separators
+
+Example:
+ openapi-schema-parser ./api-spec.yaml "# components schemas User"
+
+Note: The schema_path should start with '#' and use spaces as separators.
+`
+
+func main() {
+ if len(os.Args) < 3 {
+ fmt.Println("Error: Insufficient number of arguments")
+ fmt.Println(usage)
+ os.Exit(1)
+ }
+
+ specPath := os.Args[1]
+ schemaPath := strings.Join(os.Args[2:], " ") // Join all remaining arguments
+
+ if !strings.HasPrefix(schemaPath, "# ") {
+ fmt.Println("Error: schema_path must start with '# '")
+ fmt.Println(usage)
+ os.Exit(1)
+ }
+
+ specData, err := os.ReadFile(specPath)
+ if err != nil {
+ fmt.Printf("Error reading OpenAPI spec file: %v\n", err)
+ os.Exit(1)
+ }
+
+ var spec interface{}
+ if strings.HasSuffix(specPath, ".json") {
+ err = json.Unmarshal(specData, &spec)
+ } else {
+ err = yaml.Unmarshal(specData, &spec)
+ }
+ if err != nil {
+ fmt.Printf("Error parsing OpenAPI spec: %v\n", err)
+ os.Exit(1)
+ }
+
+ schema, err := getSchemaFromPath(spec, schemaPath)
+ if err != nil {
+ fmt.Printf("Error: %v\n", err)
+ os.Exit(1)
+ }
+
+ // jsonSchema, err := json.MarshalIndent(schema, "", " ")
+ // if err != nil {
+ // fmt.Printf("Error converting schema to JSON: %v\n", err)
+ // os.Exit(1)
+ // }
+
+ traverseProperties(schema.(map[string]interface{})["schema"].(map[string]interface{})["properties"].(map[string]interface{}), []string{})
+}
+
+func traverseProperties(m map[string]interface{}, path []string) {
+ for propName, v := range m {
+ propMap := v.(map[string]interface{})
+ fmt.Println(propName, propMap["type"])
+ }
+}
+
+func getSchemaFromPath(spec interface{}, path string) (interface{}, error) {
+ components := strings.Split(strings.TrimPrefix(path, "# "), " ")
+ current := spec
+
+ for _, component := range components {
+ switch v := current.(type) {
+ case map[interface{}]interface{}:
+ if next, ok := v[component]; ok {
+ current = next
+ } else {
+ return nil, fmt.Errorf("path component '%s' not found", component)
+ }
+ case map[string]interface{}:
+ if next, ok := v[component]; ok {
+ current = next
+ } else {
+ return nil, fmt.Errorf("path component '%s' not found", component)
+ }
+ default:
+ return nil, fmt.Errorf("invalid path: '%s' is not an object", component)
+ }
+ }
+
+ return current, nil
+}
diff --git a/openapiconverter/openapiconverter b/openapiconverter/openapiconverter
new file mode 100755
index 0000000..b4a0942
Binary files /dev/null and b/openapiconverter/openapiconverter differ