From 5e6ee989ae4d5bc8d0393dfd7f1521d43e67fe17 Mon Sep 17 00:00:00 2001 From: fredbi Date: Sun, 8 Jul 2018 00:07:26 +0200 Subject: [PATCH] Hang when expanding circular $ref * Fixes #76 (absolute path left behind in resolved circular $ref) * Fixes #74 (isCircular no more checks on basePath!="") * Contributes #75 (hang is solved, but the (always correct) expanded result may differ from one run to another) * Contributes go-swagger/go-swagger#957 (hang on circular spec) --- debug.go | 47 + debug_test.go | 59 + expander.go | 100 +- expander_test.go | 111 +- fixtures/bugs/957/fixture-957.json | 3713 ++++++++++++++++++++++ fixtures/expansion/circular-minimal.json | 58 + fixtures/expansion/circularSpec2.json | 330 ++ 7 files changed, 4364 insertions(+), 54 deletions(-) create mode 100644 debug.go create mode 100644 debug_test.go create mode 100644 fixtures/bugs/957/fixture-957.json create mode 100644 fixtures/expansion/circular-minimal.json create mode 100644 fixtures/expansion/circularSpec2.json diff --git a/debug.go b/debug.go new file mode 100644 index 0000000..7edb95a --- /dev/null +++ b/debug.go @@ -0,0 +1,47 @@ +// Copyright 2015 go-swagger maintainers +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package spec + +import ( + "fmt" + "log" + "os" + "path/filepath" + "runtime" +) + +var ( + // Debug is true when the SWAGGER_DEBUG env var is not empty. + // It enables a more verbose logging of validators. + Debug = os.Getenv("SWAGGER_DEBUG") != "" + // validateLogger is a debug logger for this package + specLogger *log.Logger +) + +func init() { + debugOptions() +} + +func debugOptions() { + specLogger = log.New(os.Stdout, "spec:", log.LstdFlags) +} + +func debugLog(msg string, args ...interface{}) { + // A private, trivial trace logger, based on go-openapi/spec/expander.go:debugLog() + if Debug { + _, file1, pos1, _ := runtime.Caller(1) + specLogger.Printf("%s:%d: %s", filepath.Base(file1), pos1, fmt.Sprintf(msg, args...)) + } +} diff --git a/debug_test.go b/debug_test.go new file mode 100644 index 0000000..74c2a78 --- /dev/null +++ b/debug_test.go @@ -0,0 +1,59 @@ +// Copyright 2015 go-swagger maintainers +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package spec + +import ( + "io/ioutil" + "os" + "sync" + "testing" + + "github.com/stretchr/testify/assert" +) + +var ( + logMutex = &sync.Mutex{} +) + +func TestDebug(t *testing.T) { + tmpFile, _ := ioutil.TempFile("", "debug-test") + tmpName := tmpFile.Name() + defer func() { + Debug = false + // mutex for -race + logMutex.Unlock() + _ = os.Remove(tmpName) + }() + + // mutex for -race + logMutex.Lock() + Debug = true + debugOptions() + defer func() { + specLogger.SetOutput(os.Stdout) + }() + + specLogger.SetOutput(tmpFile) + + debugLog("A debug") + Debug = false + _ = tmpFile.Close() + + flushed, _ := os.Open(tmpName) + buf := make([]byte, 500) + _, _ = flushed.Read(buf) + specLogger.SetOutput(os.Stdout) + assert.Contains(t, string(buf), "A debug") +} diff --git a/expander.go b/expander.go index 98629a7..f7f369f 100644 --- a/expander.go +++ b/expander.go @@ -30,11 +30,6 @@ import ( "github.com/go-openapi/swag" ) -var ( - // Debug enables logging when SWAGGER_DEBUG env var is not empty - Debug = os.Getenv("SWAGGER_DEBUG") != "" -) - // ExpandOptions provides options for expand. type ExpandOptions struct { RelativeBase string @@ -67,6 +62,21 @@ func initResolutionCache() ResolutionCache { }} } +// resolverContext allows to share a context during spec processing. +// At the moment, it just holds the index of circular references found. +type resolverContext struct { + // circulars holds all visited circular references, which allows shortcuts. + // NOTE: this is not just a performance improvement: it is required to figure out + // circular references which participate several cycles. + circulars map[string]bool +} + +func newResolverContext() *resolverContext { + return &resolverContext{ + circulars: make(map[string]bool), + } +} + // Get retrieves a cached URI func (s *simpleCache) Get(uri string) (interface{}, bool) { debugLog("getting %q from resolution cache", uri) @@ -87,7 +97,7 @@ func (s *simpleCache) Set(uri string, data interface{}) { // ResolveRefWithBase resolves a reference against a context root with preservation of base path func ResolveRefWithBase(root interface{}, ref *Ref, opts *ExpandOptions) (*Schema, error) { - resolver, err := defaultSchemaLoader(root, opts, nil) + resolver, err := defaultSchemaLoader(root, opts, nil, nil) if err != nil { return nil, err } @@ -133,7 +143,7 @@ func ResolveParameter(root interface{}, ref Ref) (*Parameter, error) { // ResolveParameterWithBase resolves a parameter reference against a context root and base path func ResolveParameterWithBase(root interface{}, ref Ref, opts *ExpandOptions) (*Parameter, error) { - resolver, err := defaultSchemaLoader(root, opts, nil) + resolver, err := defaultSchemaLoader(root, opts, nil, nil) if err != nil { return nil, err } @@ -152,7 +162,7 @@ func ResolveResponse(root interface{}, ref Ref) (*Response, error) { // ResolveResponseWithBase resolves response a reference against a context root and base path func ResolveResponseWithBase(root interface{}, ref Ref, opts *ExpandOptions) (*Response, error) { - resolver, err := defaultSchemaLoader(root, opts, nil) + resolver, err := defaultSchemaLoader(root, opts, nil, nil) if err != nil { return nil, err } @@ -166,7 +176,7 @@ func ResolveResponseWithBase(root interface{}, ref Ref, opts *ExpandOptions) (*R // ResolveItems resolves header and parameter items reference against a context root and base path func ResolveItems(root interface{}, ref Ref, opts *ExpandOptions) (*Items, error) { - resolver, err := defaultSchemaLoader(root, opts, nil) + resolver, err := defaultSchemaLoader(root, opts, nil, nil) if err != nil { return nil, err } @@ -183,7 +193,7 @@ func ResolveItems(root interface{}, ref Ref, opts *ExpandOptions) (*Items, error // ResolvePathItem resolves response a path item against a context root and base path func ResolvePathItem(root interface{}, ref Ref, opts *ExpandOptions) (*PathItem, error) { - resolver, err := defaultSchemaLoader(root, opts, nil) + resolver, err := defaultSchemaLoader(root, opts, nil, nil) if err != nil { return nil, err } @@ -202,6 +212,7 @@ type schemaLoader struct { root interface{} options *ExpandOptions cache ResolutionCache + context *resolverContext loadDoc func(string) (json.RawMessage, error) } @@ -224,7 +235,8 @@ func init() { func defaultSchemaLoader( root interface{}, expandOptions *ExpandOptions, - cache ResolutionCache) (*schemaLoader, error) { + cache ResolutionCache, + context *resolverContext) (*schemaLoader, error) { if cache == nil { cache = resCache @@ -232,11 +244,14 @@ func defaultSchemaLoader( if expandOptions == nil { expandOptions = &ExpandOptions{} } - + if context == nil { + context = newResolverContext() + } return &schemaLoader{ root: root, options: expandOptions, cache: cache, + context: context, loadDoc: func(path string) (json.RawMessage, error) { debugLog("fetching document at %q", path) return PathLoader(path) @@ -315,12 +330,6 @@ func nextRef(startingNode interface{}, startingRef *Ref, ptr *jsonpointer.Pointe return ret } -func debugLog(msg string, args ...interface{}) { - if Debug { - log.Printf(msg, args...) - } -} - // normalize absolute path for cache. // on Windows, drive letters should be converted to lower as scheme in net/url.URL func normalizeAbsPath(path string) string { @@ -369,6 +378,19 @@ func normalizePaths(refPath, base string) string { return baseURL.String() } +// denormalizePaths returns to simplest notation on file $ref, +// i.e. strips the absolute path and sets a path relative to the base path. +// +// This is currently used when we rewrite ref after a circular ref has been detected +func denormalizeFileRef(ref *Ref, relativeBase string) *Ref { + if ref.String() == "" || ref.IsRoot() || ref.HasFragmentOnly { + return ref + } + // strip relativeBase from URI + r, _ := NewRef(strings.TrimPrefix(ref.String(), relativeBase)) + return &r +} + // relativeBase could be an ABSOLUTE file path or an ABSOLUTE URL func normalizeFileRef(ref *Ref, relativeBase string) *Ref { // This is important for when the reference is pointing to the root schema @@ -377,8 +399,7 @@ func normalizeFileRef(ref *Ref, relativeBase string) *Ref { return &r } - refURL := ref.GetURL() - debugLog("normalizing %s against %s (%s)", ref.String(), relativeBase, refURL.String()) + debugLog("normalizing %s against %s (%s)", ref.String(), relativeBase, ref.GetURL().String()) s := normalizePaths(ref.String(), relativeBase) r, _ := NewRef(s) @@ -478,7 +499,7 @@ func absPath(fname string) (string, error) { // ExpandSpec expands the references in a swagger spec func ExpandSpec(spec *Swagger, options *ExpandOptions) error { - resolver, err := defaultSchemaLoader(spec, options, nil) + resolver, err := defaultSchemaLoader(spec, options, nil, nil) // Just in case this ever returns an error. if shouldStopOnError(err, resolver.options) { return err @@ -575,7 +596,7 @@ func ExpandSchemaWithBasePath(schema *Schema, cache ResolutionCache, opts *Expan basePath, _ = absPath(opts.RelativeBase) } - resolver, err := defaultSchemaLoader(nil, opts, cache) + resolver, err := defaultSchemaLoader(nil, opts, cache, nil) if err != nil { return err } @@ -627,8 +648,18 @@ func basePathFromSchemaID(oldBasePath, id string) string { return u.String() } -func isCircular(ref *Ref, basePath string, parentRefs ...string) bool { - return basePath != "" && swag.ContainsStringsCI(parentRefs, ref.String()) +func (r *schemaLoader) isCircular(ref *Ref, basePath string, parentRefs ...string) (foundCycle bool) { + normalizedRef := normalizePaths(ref.String(), basePath) + if _, ok := r.context.circulars[normalizedRef]; ok { + // circular $ref has been already detected in another explored cycle + foundCycle = true + return + } + foundCycle = swag.ContainsStringsCI(parentRefs, normalizedRef) + if foundCycle { + r.context.circulars[normalizedRef] = true + } + return } func expandSchema(target Schema, parentRefs []string, resolver *schemaLoader, basePath string) (*Schema, error) { @@ -666,12 +697,14 @@ func expandSchema(target Schema, parentRefs []string, resolver *schemaLoader, ba /* this means there is a circle in the recursion tree */ /* return the Ref */ - if isCircular(normalizedRef, basePath, parentRefs...) { - target.Ref = *normalizedRef + if resolver.isCircular(normalizedRef, basePath, parentRefs...) { + debugLog("shortcut circular ref") + // circular refs cannot be expanded. We leave them as ref + target.Ref = *denormalizeFileRef(normalizedRef, basePath) return &target, nil } - debugLog("\nbasePath: %s", basePath) + debugLog("basePath: %s", basePath) if Debug { b, _ := json.Marshal(target) debugLog("calling Resolve with target: %s", string(b)) @@ -687,7 +720,6 @@ func expandSchema(target Schema, parentRefs []string, resolver *schemaLoader, ba if shouldStopOnError(err, resolver.options) { return nil, err } - return expandSchema(*t, parentRefs, resolver, normalizedBasePath) } } @@ -797,7 +829,7 @@ func derefPathItem(pathItem *PathItem, parentRefs []string, resolver *schemaLoad normalizedRef := normalizeFileRef(&pathItem.Ref, basePath) normalizedBasePath := normalizedRef.RemoteURI() - if isCircular(normalizedRef, basePath, parentRefs...) { + if resolver.isCircular(normalizedRef, basePath, parentRefs...) { return nil } @@ -904,7 +936,7 @@ func transitiveResolver(basePath string, ref Ref, resolver *schemaLoader) (*sche rootURL.Fragment = "" root, _ := resolver.cache.Get(rootURL.String()) var err error - resolver, err = defaultSchemaLoader(root, resolver.options, resolver.cache) + resolver, err = defaultSchemaLoader(root, resolver.options, resolver.cache, resolver.context) if err != nil { return nil, err } @@ -920,7 +952,7 @@ func ExpandResponse(response *Response, basePath string) error { opts := &ExpandOptions{ RelativeBase: basePath, } - resolver, err := defaultSchemaLoader(nil, opts, nil) + resolver, err := defaultSchemaLoader(nil, opts, nil, nil) if err != nil { return err } @@ -935,7 +967,7 @@ func derefResponse(response *Response, parentRefs []string, resolver *schemaLoad normalizedRef := normalizeFileRef(&response.Ref, basePath) normalizedBasePath := normalizedRef.RemoteURI() - if isCircular(normalizedRef, basePath, parentRefs...) { + if resolver.isCircular(normalizedRef, basePath, parentRefs...) { return nil } @@ -990,7 +1022,7 @@ func ExpandParameter(parameter *Parameter, basePath string) error { opts := &ExpandOptions{ RelativeBase: basePath, } - resolver, err := defaultSchemaLoader(nil, opts, nil) + resolver, err := defaultSchemaLoader(nil, opts, nil, nil) if err != nil { return err } @@ -1004,7 +1036,7 @@ func derefParameter(parameter *Parameter, parentRefs []string, resolver *schemaL normalizedRef := normalizeFileRef(¶meter.Ref, basePath) normalizedBasePath := normalizedRef.RemoteURI() - if isCircular(normalizedRef, basePath, parentRefs...) { + if resolver.isCircular(normalizedRef, basePath, parentRefs...) { return nil } diff --git a/expander_test.go b/expander_test.go index 38f0d0f..82f4295 100644 --- a/expander_test.go +++ b/expander_test.go @@ -17,8 +17,11 @@ package spec import ( "encoding/json" "io/ioutil" + "log" "net/http" "net/http/httptest" + "os" + "path/filepath" "runtime" "testing" @@ -138,7 +141,7 @@ func TestExpandResponseSchema(t *testing.T) { func TestSpecExpansion(t *testing.T) { spec := new(Swagger) - // resolver, err := defaultSchemaLoader(spec, nil, nil) + // resolver, err := defaultSchemaLoader(spec, nil, nil,nil) // assert.NoError(t, err) err := ExpandSpec(spec, nil) @@ -210,7 +213,7 @@ func TestResponseExpansion(t *testing.T) { err = json.Unmarshal(specDoc, spec) assert.NoError(t, err) - resolver, err := defaultSchemaLoader(spec, nil, nil) + resolver, err := defaultSchemaLoader(spec, nil, nil, nil) assert.NoError(t, err) resp := spec.Responses["anotherPet"] @@ -311,7 +314,7 @@ func TestParameterExpansion(t *testing.T) { basePath, err := absPath("fixtures/expansion/params.json") assert.NoError(t, err) - resolver, err := defaultSchemaLoader(spec, nil, nil) + resolver, err := defaultSchemaLoader(spec, nil, nil, nil) assert.NoError(t, err) param := spec.Parameters["query"] @@ -365,7 +368,7 @@ func TestCircularRefsExpansion(t *testing.T) { err = json.Unmarshal(carsDoc, spec) assert.NoError(t, err) - resolver, err := defaultSchemaLoader(spec, nil, nil) + resolver, err := defaultSchemaLoader(spec, nil, nil, nil) assert.NoError(t, err) schema := spec.Definitions["car"] @@ -375,7 +378,75 @@ func TestCircularRefsExpansion(t *testing.T) { }, "Calling expand schema with circular refs, should not panic!") } +func TestCircularSpec2Expansion(t *testing.T) { + // TODO: assert repeatable result + fixturePath := filepath.Join("fixtures", "expansion", "circular-minimal.json") + jazon := expandThisOrDieTrying(t, fixturePath) + // assert stripped $ref in result + assert.NotContainsf(t, jazon, "circular-minimal.json#/", + "expected %s to be expanded with stripped circular $ref", fixturePath) + + fixturePath = "fixtures/expansion/circularSpec2.json" + jazon = expandThisOrDieTrying(t, fixturePath) + assert.NotContainsf(t, jazon, "circularSpec.json#/", + "expected %s to be expanded with stripped circular $ref", fixturePath) + + fixturePath = "fixtures/bugs/957/fixture-957.json" + jazon = expandThisOrDieTrying(t, fixturePath) + assert.NotContainsf(t, jazon, "fixture-957.json#/", + "expected %s to be expanded with stripped circular $ref", fixturePath) + /* + + At the moment, the result of expanding circular references is not stable, when several cycles have intersections: + the spec structure is randomly walked through and mutating as expansion is carried out. + detected cycles in $ref are not necessarily the shortest matches. + + This may result in different, functionally correct expanded spec (e.g. with same validations) + + for i := 0; i < 1; i++ { + bbb := expandThisOrDieTrying(t, fixturePath) + t.Log(bbb) + if !assert.JSONEqf(t, jazon, bbb, "on iteration %d, we should have stable expanded spec", i) { + t.FailNow() + return + } + } + */ +} + +func expandThisOrDieTrying(t *testing.T, fixturePath string) string { + doc, err := jsonDoc(fixturePath) + if !assert.NoError(t, err) { + t.FailNow() + return "" + } + + specPath, _ := absPath(fixturePath) + + opts := &ExpandOptions{ + RelativeBase: specPath, + } + + spec := new(Swagger) + err = json.Unmarshal(doc, spec) + if !assert.NoError(t, err) { + t.FailNow() + return "" + } + + assert.NotPanics(t, func() { + err = ExpandSpec(spec, opts) + assert.NoError(t, err) + }, "Calling expand spec with circular refs, should not panic!") + + bbb, _ := json.MarshalIndent(spec, "", " ") + return string(bbb) +} + func TestContinueOnErrorExpansion(t *testing.T) { + defer log.SetOutput(os.Stdout) + log.SetOutput(ioutil.Discard) + missingRefDoc, err := jsonDoc("fixtures/expansion/missingRef.json") assert.NoError(t, err) @@ -459,7 +530,7 @@ func TestItemsExpansion(t *testing.T) { err = json.Unmarshal(carsDoc, spec) assert.NoError(t, err) - resolver, err := defaultSchemaLoader(spec, nil, nil) + resolver, err := defaultSchemaLoader(spec, nil, nil, nil) assert.NoError(t, err) schema := spec.Definitions["car"] @@ -586,7 +657,7 @@ func TestSchemaExpansion(t *testing.T) { err = json.Unmarshal(carsDoc, spec) assert.NoError(t, err) - resolver, err := defaultSchemaLoader(spec, nil, nil) + resolver, err := defaultSchemaLoader(spec, nil, nil, nil) assert.NoError(t, err) schema := spec.Definitions["car"] @@ -732,7 +803,7 @@ func TestRelativeBaseURI(t *testing.T) { defer server.Close() spec := new(Swagger) - // resolver, err := defaultSchemaLoader(spec, nil, nil) + // resolver, err := defaultSchemaLoader(spec, nil, nil,nil) // assert.NoError(t, err) err := ExpandSpec(spec, nil) @@ -874,7 +945,7 @@ func TestResolveRemoteRef_RootSame(t *testing.T) { if assert.NoError(t, err) && assert.NoError(t, json.Unmarshal(b, rootDoc)) { var result0 Swagger ref0, _ := NewRef(server.URL + "/refed.json#") - resolver0, _ := defaultSchemaLoader(rootDoc, nil, nil) + resolver0, _ := defaultSchemaLoader(rootDoc, nil, nil, nil) if assert.NoError(t, resolver0.Resolve(&ref0, &result0, "")) { assertSpecs(t, result0, *rootDoc) } @@ -883,7 +954,7 @@ func TestResolveRemoteRef_RootSame(t *testing.T) { ref1, _ := NewRef("./refed.json") resolver1, _ := defaultSchemaLoader(rootDoc, &ExpandOptions{ RelativeBase: specBase, - }, nil) + }, nil, nil) if assert.NoError(t, resolver1.Resolve(&ref1, &result1, specBase)) { assertSpecs(t, result1, *rootDoc) } @@ -923,7 +994,7 @@ func TestResolveRemoteRef_FromInvalidFragment(t *testing.T) { var tgt Schema ref, err := NewRef(server.URL + "/refed.json#/definitions/NotThere") if assert.NoError(t, err) { - resolver, _ := defaultSchemaLoader(rootDoc, nil, nil) + resolver, _ := defaultSchemaLoader(rootDoc, nil, nil, nil) assert.Error(t, resolver.Resolve(&ref, &tgt, "")) } } @@ -997,7 +1068,7 @@ func TestResolveRemoteRef_WithNestedResolutionContextWithFragment(t *testing.T) // var tgt Schema // ref, err := NewRef(server.URL + "/resolution2.json#/items/items") // if assert.NoError(t, err) { -// resolver, _ := defaultSchemaLoader(rootDoc, nil, nil) +// resolver, _ := defaultSchemaLoader(rootDoc, nil, nil,nil) // if assert.NoError(t, resolver.Resolve(&ref, &tgt, "")) { // assert.Equal(t, StringOrArray([]string{"file"}), tgt.Type) // } @@ -1018,7 +1089,7 @@ func TestResolveRemoteRef_ToParameter(t *testing.T) { ref, err := NewRef(server.URL + "/refed.json#/parameters/idParam") if assert.NoError(t, err) { - resolver, _ := defaultSchemaLoader(rootDoc, nil, nil) + resolver, _ := defaultSchemaLoader(rootDoc, nil, nil, nil) if assert.NoError(t, resolver.Resolve(&ref, &tgt, "")) { assert.Equal(t, "id", tgt.Name) assert.Equal(t, "path", tgt.In) @@ -1044,7 +1115,7 @@ func TestResolveRemoteRef_ToPathItem(t *testing.T) { ref, err := NewRef(server.URL + "/refed.json#/paths/" + jsonpointer.Escape("/pets/{id}")) if assert.NoError(t, err) { - resolver, _ := defaultSchemaLoader(rootDoc, nil, nil) + resolver, _ := defaultSchemaLoader(rootDoc, nil, nil, nil) if assert.NoError(t, resolver.Resolve(&ref, &tgt, "")) { assert.Equal(t, rootDoc.Paths.Paths["/pets/{id}"].Get, tgt.Get) } @@ -1065,7 +1136,7 @@ func TestResolveRemoteRef_ToResponse(t *testing.T) { ref, err := NewRef(server.URL + "/refed.json#/responses/petResponse") if assert.NoError(t, err) { - resolver, _ := defaultSchemaLoader(rootDoc, nil, nil) + resolver, _ := defaultSchemaLoader(rootDoc, nil, nil, nil) if assert.NoError(t, resolver.Resolve(&ref, &tgt, "")) { assert.Equal(t, rootDoc.Responses["petResponse"], tgt) } @@ -1079,7 +1150,7 @@ func TestResolveLocalRef_SameRoot(t *testing.T) { result := new(Swagger) ref, _ := NewRef("#") - resolver, _ := defaultSchemaLoader(rootDoc, nil, nil) + resolver, _ := defaultSchemaLoader(rootDoc, nil, nil, nil) err := resolver.Resolve(&ref, result, "") if assert.NoError(t, err) { assert.Equal(t, rootDoc, result) @@ -1093,7 +1164,7 @@ func TestResolveLocalRef_FromFragment(t *testing.T) { var tgt Schema ref, err := NewRef("#/definitions/Category") if assert.NoError(t, err) { - resolver, _ := defaultSchemaLoader(rootDoc, nil, nil) + resolver, _ := defaultSchemaLoader(rootDoc, nil, nil, nil) err := resolver.Resolve(&ref, &tgt, "") if assert.NoError(t, err) { assert.Equal(t, "Category", tgt.ID) @@ -1108,7 +1179,7 @@ func TestResolveLocalRef_FromInvalidFragment(t *testing.T) { var tgt Schema ref, err := NewRef("#/definitions/NotThere") if assert.NoError(t, err) { - resolver, _ := defaultSchemaLoader(rootDoc, nil, nil) + resolver, _ := defaultSchemaLoader(rootDoc, nil, nil, nil) err := resolver.Resolve(&ref, &tgt, "") assert.Error(t, err) } @@ -1122,7 +1193,7 @@ func TestResolveLocalRef_Parameter(t *testing.T) { var tgt Parameter ref, err := NewRef("#/parameters/idParam") if assert.NoError(t, err) { - resolver, _ := defaultSchemaLoader(rootDoc, nil, nil) + resolver, _ := defaultSchemaLoader(rootDoc, nil, nil, nil) if assert.NoError(t, resolver.Resolve(&ref, &tgt, basePath)) { assert.Equal(t, "id", tgt.Name) assert.Equal(t, "path", tgt.In) @@ -1143,7 +1214,7 @@ func TestResolveLocalRef_PathItem(t *testing.T) { var tgt PathItem ref, err := NewRef("#/paths/" + jsonpointer.Escape("/pets/{id}")) if assert.NoError(t, err) { - resolver, _ := defaultSchemaLoader(rootDoc, nil, nil) + resolver, _ := defaultSchemaLoader(rootDoc, nil, nil, nil) if assert.NoError(t, resolver.Resolve(&ref, &tgt, basePath)) { assert.Equal(t, rootDoc.Paths.Paths["/pets/{id}"].Get, tgt.Get) } @@ -1159,7 +1230,7 @@ func TestResolveLocalRef_Response(t *testing.T) { var tgt Response ref, err := NewRef("#/responses/petResponse") if assert.NoError(t, err) { - resolver, _ := defaultSchemaLoader(rootDoc, nil, nil) + resolver, _ := defaultSchemaLoader(rootDoc, nil, nil, nil) if assert.NoError(t, resolver.Resolve(&ref, &tgt, basePath)) { assert.Equal(t, rootDoc.Responses["petResponse"], tgt) } diff --git a/fixtures/bugs/957/fixture-957.json b/fixtures/bugs/957/fixture-957.json new file mode 100644 index 0000000..2de6bb4 --- /dev/null +++ b/fixtures/bugs/957/fixture-957.json @@ -0,0 +1,3713 @@ +{ + "info": { + "title": "API title", + "version": "0.0.1" + }, + "swagger": "2.0", + "produces": [ + "application/json", + "text/plain" + ], + "securityDefinitions": { + "api_key": { + "type": "apiKey", + "name": "private_token", + "in": "query" + }, + "oauth2": { + "type": "oauth2", + "authorizationUrl": "https://local.tools.stack.local/torca/oauth/authorize", + "flow": "implicit" + } + }, + "host": "local.tools.stack.local", + "basePath": "/torca/nmdb/api", + "schemes": [ + "https" + ], + "tags": [ + { + "name": "devices", + "description": "Operations about devices" + }, + { + "name": "info", + "description": "Operations about infos" + } + ], + "paths": { + "/v2/devices": { + "get": { + "summary": "Query Nmdb::Device Object.", + "description": "Query Nmdb::Device Object.", + "produces": [ + "application/json" + ], + "parameters": [ + { + "in": "query", + "name": "page", + "description": "Page offset to fetch.", + "type": "integer", + "format": "int32", + "default": 1, + "required": false + }, + { + "in": "query", + "name": "per_page", + "description": "Number of results to return per page.", + "type": "integer", + "format": "int32", + "default": 20, + "required": false + }, + { + "in": "query", + "name": "offset", + "description": "Pad a number of results.", + "type": "integer", + "format": "int32", + "default": 0, + "required": false + }, + { + "in": "query", + "name": "fmt", + "type": "string", + "default": "full_root", + "enum": [ + "full", + "full_root", + "base" + ], + "required": false + }, + { + "in": "query", + "name": "rels", + "description": "Comma-separated list of relationships. Maximum 5 levels. \n e.g. interfaces,interfaces.ip_address", + "type": "string", + "required": false + }, + { + "in": "query", + "name": "filters", + "description": "Supports nesting up to 2 levels. \n e.g {\"host_name\":\"~hhcvi\",\"interfaces\":{\"ip_address\":{\"network_address\":\"~10.10.10\"},\"name\":\"eth0\"}}", + "type": "string", + "required": false + }, + { + "in": "query", + "name": "search", + "type": "string", + "required": false + } + ], + "responses": { + "200": { + "description": "Query Nmdb::Device Object.", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/Device" + } + } + }, + "406": { + "description": "NmdbQueryError", + "schema": { + "$ref": "#/definitions/NmdbQueryError" + } + } + }, + "tags": [ + "devices" + ], + "operationId": "getV2Devices" + }, + "post": { + "summary": "Create Nmdb::Device Object.", + "description": "Create Nmdb::Device Object.", + "produces": [ + "application/json" + ], + "consumes": [ + "application/json" + ], + "parameters": [ + { + "name": "V2Devices", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/postV2Devices" + } + } + ], + "responses": { + "201": { + "description": "Create Nmdb::Device Object.", + "schema": { + "$ref": "#/definitions/Device" + } + } + }, + "tags": [ + "devices" + ], + "operationId": "postV2Devices" + } + }, + "/v2/devices/{id}": { + "get": { + "summary": "GET Nmdb::Device Object.", + "description": "GET Nmdb::Device Object.", + "produces": [ + "application/json" + ], + "parameters": [ + { + "in": "path", + "name": "id", + "type": "integer", + "format": "int32", + "required": true + }, + { + "in": "query", + "name": "fmt", + "type": "string", + "default": "full_root", + "enum": [ + "full", + "full_root", + "base" + ], + "required": false + }, + { + "in": "query", + "name": "rels", + "description": "Comma-separated list of relationships. Maximum 5 levels. \n e.g. interfaces,interfaces.ip_address", + "type": "string", + "required": false + } + ], + "responses": { + "200": { + "description": "GET Nmdb::Device Object.", + "schema": { + "$ref": "#/definitions/Device" + } + }, + "406": { + "description": "NmdbQueryError", + "schema": { + "$ref": "#/definitions/NmdbQueryError" + } + } + }, + "tags": [ + "devices" + ], + "operationId": "getV2DevicesId" + }, + "put": { + "summary": "Update Nmdb::Device Object.", + "description": "Update Nmdb::Device Object.", + "produces": [ + "application/json" + ], + "consumes": [ + "application/json" + ], + "parameters": [ + { + "in": "path", + "name": "id", + "type": "integer", + "format": "int32", + "required": true + }, + { + "name": "V2Devices", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/putV2Devices" + } + } + ], + "responses": { + "200": { + "description": "Update Nmdb::Device Object.", + "schema": { + "$ref": "#/definitions/Device" + } + } + }, + "tags": [ + "devices" + ], + "operationId": "putV2DevicesId" + } + }, + "/v2/info/version": { + "get": { + "summary": "Get API Version", + "description": "Get API Version", + "produces": [ + "application/json" + ], + "responses": { + "200": { + "description": "Get API Version", + "schema": { + "$ref": "#/definitions/Version" + } + } + }, + "tags": [ + "info" + ], + "operationId": "getV2InfoVersion" + } + } + }, + "definitions": { + "Device": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "ciid": { + "type": "string" + }, + "host_name": { + "type": "string" + }, + "description": { + "type": "string" + }, + "zone_id": { + "type": "integer", + "format": "int32" + }, + "project_id": { + "type": "integer", + "format": "int32" + }, + "device_model_id": { + "type": "integer", + "format": "int32" + }, + "rack_id": { + "type": "integer", + "format": "int32" + }, + "device_status_id": { + "type": "integer", + "format": "int32" + }, + "device_status_reason_id": { + "type": "integer", + "format": "int32" + }, + "created_at": { + "type": "string", + "format": "date-time" + }, + "updated_at": { + "type": "string", + "format": "date-time" + }, + "asset_tag": { + "type": "string" + }, + "reconciliation_identity": { + "type": "string" + }, + "serial_number": { + "type": "string" + }, + "application_environment_id": { + "type": "integer", + "format": "int32" + }, + "pod_id": { + "type": "integer", + "format": "int32" + }, + "vm_capacity": { + "type": "integer", + "format": "int32" + }, + "switch_domain_id": { + "type": "integer", + "format": "int32" + }, + "blade_slot": { + "type": "integer", + "format": "int32" + }, + "blade_slots_required": { + "type": "integer", + "format": "int32" + }, + "blade_chassis_id": { + "type": "integer", + "format": "int32" + }, + "virtual_host_id": { + "type": "integer", + "format": "int32" + }, + "physical_host_id": { + "type": "integer", + "format": "int32" + }, + "blade_capacity": { + "type": "integer", + "format": "int32" + }, + "device_type_id": { + "type": "integer", + "format": "int32" + }, + "ru_required": { + "type": "integer", + "format": "int32" + }, + "primary_device_id": { + "type": "integer", + "format": "int32" + }, + "instance_id": { + "type": "string" + }, + "operating_system_id": { + "type": "integer", + "format": "int32" + }, + "workbook_version": { + "type": "string" + }, + "virtualized_on_vm_host_pool_id": { + "type": "integer", + "format": "int32" + }, + "contained_in_vm_host_pool_id": { + "type": "integer", + "format": "int32" + }, + "a_or_b": { + "type": "integer", + "format": "int32" + }, + "bottom_ru": { + "type": "integer", + "format": "int32" + }, + "event_logs": { + "type": "array", + "items": { + "$ref": "#/definitions/EventLog" + } + }, + "sync_status": { + "$ref": "#/definitions/SyncStatus" + }, + "device_status": { + "$ref": "#/definitions/DeviceStatus" + }, + "device_status_reason": { + "$ref": "#/definitions/DeviceStatusReason" + }, + "versions": { + "type": "array", + "items": { + "$ref": "#/definitions/Version" + } + }, + "device_model": { + "$ref": "#/definitions/DeviceModel" + }, + "device_type": { + "$ref": "#/definitions/DeviceType" + }, + "project": { + "$ref": "#/definitions/Project" + }, + "rack": { + "$ref": "#/definitions/Rack" + }, + "zone": { + "$ref": "#/definitions/Zone" + }, + "pod": { + "$ref": "#/definitions/Pod" + }, + "application_environment": { + "$ref": "#/definitions/ApplicationEnvironment" + }, + "operating_system": { + "$ref": "#/definitions/OperatingSystem" + }, + "host_name_reservation": { + "$ref": "#/definitions/HostNameReservation" + }, + "interfaces": { + "type": "array", + "items": { + "$ref": "#/definitions/Interface" + } + }, + "switch_ports": { + "type": "array", + "items": { + "$ref": "#/definitions/SwitchPort" + } + }, + "nat_entries": { + "type": "array", + "items": { + "$ref": "#/definitions/NatEntry" + } + }, + "load_balancer_entries": { + "type": "array", + "items": { + "$ref": "#/definitions/LoadBalancerEntry" + } + }, + "blades": { + "type": "array", + "items": { + "$ref": "#/definitions/Device" + } + }, + "blade_chassis": { + "$ref": "#/definitions/Device" + }, + "virtual_clients": { + "type": "array", + "items": { + "$ref": "#/definitions/Device" + } + }, + "virtual_host": { + "$ref": "#/definitions/Device" + }, + "virtual_hosts": { + "type": "array", + "items": { + "$ref": "#/definitions/Device" + } + }, + "physical_host": { + "$ref": "#/definitions/Device" + }, + "host_pool": { + "$ref": "#/definitions/VmHostPool" + }, + "virtualization_pool": { + "$ref": "#/definitions/VmHostPool" + }, + "primary_device": { + "$ref": "#/definitions/Device" + }, + "subnet_assignments": { + "type": "array", + "items": { + "$ref": "#/definitions/SubnetAssignment" + } + }, + "subnets": { + "$ref": "#/definitions/Subnet" + } + }, + "description": "Update Nmdb::Device Object." + }, + "EventLog": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "event_class": { + "type": "string" + }, + "severity": { + "type": "integer", + "format": "int32" + }, + "name": { + "type": "string" + }, + "status": { + "type": "string" + }, + "details": { + "type": "string" + }, + "data": { + "type": "string" + }, + "loggable_id": { + "type": "integer", + "format": "int32" + }, + "loggable_type": { + "type": "string" + }, + "start_time": { + "type": "string", + "format": "date-time" + }, + "end_time": { + "type": "string", + "format": "date-time" + }, + "created_at": { + "type": "string", + "format": "date-time" + }, + "updated_at": { + "type": "string", + "format": "date-time" + }, + "loggable": { + "$ref": "#/definitions/Loggable" + } + } + }, + "Loggable": { + "type": "object", + "properties": { + "id": { + "type": "string" + } + } + }, + "SyncStatus": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "status": { + "type": "string" + }, + "locked": { + "type": "boolean" + }, + "details": { + "type": "string" + }, + "last_sync_start": { + "type": "string", + "format": "date-time" + }, + "last_sync_end": { + "type": "string", + "format": "date-time" + }, + "synchronizable_id": { + "type": "integer", + "format": "int32" + }, + "synchronizable_type": { + "type": "string" + }, + "created_at": { + "type": "string", + "format": "date-time" + }, + "updated_at": { + "type": "string", + "format": "date-time" + }, + "synchronizable": { + "$ref": "#/definitions/Synchronizable" + } + } + }, + "Synchronizable": { + "type": "object", + "properties": { + "id": { + "type": "string" + } + } + }, + "DeviceStatus": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "name": { + "type": "string" + }, + "color": { + "type": "string" + }, + "created_at": { + "type": "string", + "format": "date-time" + }, + "updated_at": { + "type": "string", + "format": "date-time" + }, + "integration_id": { + "type": "string" + }, + "devices": { + "type": "array", + "items": { + "$ref": "#/definitions/Device" + } + }, + "racks": { + "type": "array", + "items": { + "$ref": "#/definitions/Rack" + } + }, + "device_status_reasons": { + "type": "array", + "items": { + "$ref": "#/definitions/DeviceStatusReason" + } + } + } + }, + "Rack": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "ciid": { + "type": "string" + }, + "name": { + "type": "string" + }, + "description": { + "type": "string" + }, + "width": { + "type": "string" + }, + "height": { + "type": "string" + }, + "depth": { + "type": "string" + }, + "total_ru_space": { + "type": "integer", + "format": "int32" + }, + "max_power_watts": { + "type": "string" + }, + "created_at": { + "type": "string", + "format": "date-time" + }, + "updated_at": { + "type": "string", + "format": "date-time" + }, + "location_id": { + "type": "integer", + "format": "int32" + }, + "fibre_connection_count": { + "type": "integer", + "format": "int32" + }, + "ethernet_connection_count": { + "type": "integer", + "format": "int32" + }, + "device_status_id": { + "type": "integer", + "format": "int32" + }, + "device_status_reason_id": { + "type": "integer", + "format": "int32" + }, + "pod_id": { + "type": "integer", + "format": "int32" + }, + "reconciliation_identity": { + "type": "string" + }, + "event_logs": { + "type": "array", + "items": { + "$ref": "#/definitions/EventLog" + } + }, + "sync_status": { + "$ref": "#/definitions/SyncStatus" + }, + "device_status": { + "$ref": "#/definitions/DeviceStatus" + }, + "device_status_reason": { + "$ref": "#/definitions/DeviceStatusReason" + }, + "devices": { + "type": "array", + "items": { + "$ref": "#/definitions/Device" + } + }, + "location": { + "$ref": "#/definitions/Location" + }, + "pod": { + "$ref": "#/definitions/Pod" + } + } + }, + "DeviceStatusReason": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "name": { + "type": "string" + }, + "created_at": { + "type": "string", + "format": "date-time" + }, + "updated_at": { + "type": "string", + "format": "date-time" + }, + "device_status_id": { + "type": "integer", + "format": "int32" + }, + "integration_id": { + "type": "string" + }, + "devices": { + "type": "array", + "items": { + "$ref": "#/definitions/Device" + } + }, + "racks": { + "type": "array", + "items": { + "$ref": "#/definitions/Rack" + } + }, + "device_status": { + "$ref": "#/definitions/DeviceStatus" + } + } + }, + "Location": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "site": { + "type": "string" + }, + "region": { + "type": "string" + }, + "building": { + "type": "string" + }, + "floor": { + "type": "string" + }, + "room": { + "type": "string" + }, + "latitude": { + "type": "string" + }, + "longitude": { + "type": "string" + }, + "created_at": { + "type": "string", + "format": "date-time" + }, + "updated_at": { + "type": "string", + "format": "date-time" + }, + "pods": { + "type": "array", + "items": { + "$ref": "#/definitions/Pod" + } + } + } + }, + "Pod": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "name": { + "type": "string" + }, + "pod_type_id": { + "type": "integer", + "format": "int32" + }, + "environment_id": { + "type": "integer", + "format": "int32" + }, + "created_at": { + "type": "string", + "format": "date-time" + }, + "updated_at": { + "type": "string", + "format": "date-time" + }, + "location_id": { + "type": "integer", + "format": "int32" + }, + "pod_type": { + "$ref": "#/definitions/PodType" + }, + "location": { + "$ref": "#/definitions/Location" + }, + "zones": { + "type": "array", + "items": { + "$ref": "#/definitions/Zone" + } + }, + "devices": { + "type": "array", + "items": { + "$ref": "#/definitions/Device" + } + }, + "racks": { + "type": "array", + "items": { + "$ref": "#/definitions/Rack" + } + }, + "data_transactions": { + "type": "array", + "items": { + "$ref": "#/definitions/DataTransaction" + } + } + } + }, + "PodType": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "name": { + "type": "string" + }, + "created_at": { + "type": "string", + "format": "date-time" + }, + "updated_at": { + "type": "string", + "format": "date-time" + }, + "pods": { + "type": "array", + "items": { + "$ref": "#/definitions/Pod" + } + } + } + }, + "Zone": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "name": { + "type": "string" + }, + "parent_id": { + "type": "integer", + "format": "int32" + }, + "pod_id": { + "type": "integer", + "format": "int32" + }, + "created_at": { + "type": "string", + "format": "date-time" + }, + "updated_at": { + "type": "string", + "format": "date-time" + }, + "zone_group_id": { + "type": "integer", + "format": "int32" + }, + "notes": { + "type": "string" + }, + "devices": { + "type": "array", + "items": { + "$ref": "#/definitions/Device" + } + }, + "vlans": { + "type": "array", + "items": { + "$ref": "#/definitions/Vlan" + } + }, + "subnets": { + "type": "array", + "items": { + "$ref": "#/definitions/Subnet" + } + }, + "pod": { + "$ref": "#/definitions/Pod" + }, + "children": { + "type": "array", + "items": { + "$ref": "#/definitions/Zone" + } + }, + "data_transactions": { + "type": "array", + "items": { + "$ref": "#/definitions/DataTransaction" + } + }, + "parent": { + "$ref": "#/definitions/Zone" + } + } + }, + "Vlan": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "primary_number": { + "type": "integer", + "format": "int32" + }, + "number": { + "type": "integer", + "format": "int32" + }, + "zone_id": { + "type": "integer", + "format": "int32" + }, + "created_at": { + "type": "string", + "format": "date-time" + }, + "updated_at": { + "type": "string", + "format": "date-time" + }, + "direction_id": { + "type": "integer", + "format": "int32" + }, + "vlan_type_id": { + "type": "integer", + "format": "int32" + }, + "description": { + "type": "string" + }, + "is_primary": { + "type": "boolean" + }, + "notes": { + "type": "array", + "items": { + "$ref": "#/definitions/Note" + } + }, + "subnets": { + "type": "array", + "items": { + "$ref": "#/definitions/Subnet" + } + }, + "zone": { + "$ref": "#/definitions/Zone" + }, + "direction": { + "$ref": "#/definitions/Direction" + }, + "vlan_type": { + "$ref": "#/definitions/VlanType" + }, + "interfaces": { + "type": "array", + "items": { + "$ref": "#/definitions/Interface" + } + }, + "switch_ports": { + "type": "array", + "items": { + "$ref": "#/definitions/SwitchPort" + } + }, + "data_transactions": { + "type": "array", + "items": { + "$ref": "#/definitions/DataTransaction" + } + } + } + }, + "Note": { + "type": "object", + "properties": { + "id": { + "type": "string" + } + } + }, + "Subnet": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "name": { + "type": "string" + }, + "description": { + "type": "string" + }, + "network_address": { + "type": "string" + }, + "netmask": { + "type": "integer", + "format": "int32" + }, + "default_gateway_id": { + "type": "string" + }, + "broadcast": { + "type": "string" + }, + "zone_id": { + "type": "integer", + "format": "int32" + }, + "supernet_id": { + "type": "integer", + "format": "int32" + }, + "created_at": { + "type": "string", + "format": "date-time" + }, + "updated_at": { + "type": "string", + "format": "date-time" + }, + "default_gateway": { + "type": "string" + }, + "vlan_id": { + "type": "integer", + "format": "int32" + }, + "direction_id": { + "type": "integer", + "format": "int32" + }, + "int_address": { + "type": "string" + }, + "cidr_address": { + "type": "string" + }, + "zone": { + "$ref": "#/definitions/Zone" + }, + "vlan": { + "$ref": "#/definitions/Vlan" + }, + "direction": { + "$ref": "#/definitions/Direction" + }, + "ip_addresses": { + "type": "array", + "items": { + "$ref": "#/definitions/IpAddress" + } + }, + "data_transactions": { + "type": "array", + "items": { + "$ref": "#/definitions/DataTransaction" + } + }, + "subnets": { + "type": "array", + "items": { + "$ref": "#/definitions/Subnet" + } + }, + "supernet": { + "$ref": "#/definitions/Subnet" + }, + "devices": { + "$ref": "#/definitions/Device" + }, + "versions": { + "type": "array", + "items": { + "$ref": "#/definitions/Version" + } + } + } + }, + "Direction": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "name": { + "type": "string" + }, + "zone_group_id": { + "type": "integer", + "format": "int32" + }, + "notes": { + "type": "string" + }, + "dns_suffix": { + "type": "string" + }, + "created_at": { + "type": "string", + "format": "date-time" + }, + "updated_at": { + "type": "string", + "format": "date-time" + }, + "vlans": { + "type": "array", + "items": { + "$ref": "#/definitions/Vlan" + } + }, + "interfaces": { + "type": "array", + "items": { + "$ref": "#/definitions/Interface" + } + }, + "subnets": { + "type": "array", + "items": { + "$ref": "#/definitions/Subnet" + } + }, + "data_transactions": { + "type": "array", + "items": { + "$ref": "#/definitions/DataTransaction" + } + } + } + }, + "Interface": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "mac_address": { + "type": "string" + }, + "name": { + "type": "string" + }, + "device_id": { + "type": "integer", + "format": "int32" + }, + "created_at": { + "type": "string", + "format": "date-time" + }, + "updated_at": { + "type": "string", + "format": "date-time" + }, + "require_ip": { + "type": "boolean" + }, + "require_switch_port": { + "type": "boolean" + }, + "require_default_gateway": { + "type": "boolean" + }, + "notes": { + "type": "string" + }, + "media": { + "type": "integer", + "format": "int32" + }, + "vlan_direction_id": { + "type": "integer", + "format": "int32" + }, + "interface_speed_id": { + "type": "integer", + "format": "int32" + }, + "vlan_id": { + "type": "integer", + "format": "int32" + }, + "subnet_id": { + "type": "integer", + "format": "int32" + }, + "direction_id": { + "type": "integer", + "format": "int32" + }, + "duplex_id": { + "type": "integer", + "format": "int32" + }, + "medium_id": { + "type": "integer", + "format": "int32" + }, + "switch_port_id": { + "type": "integer", + "format": "int32" + }, + "pci_slot": { + "type": "string" + }, + "a_or_b": { + "type": "integer", + "format": "int32" + }, + "require_route_for_management": { + "type": "boolean" + }, + "require_route_for_getronics": { + "type": "boolean" + }, + "default_gateway_id": { + "type": "integer", + "format": "int32" + }, + "static_routes": { + "type": "string" + }, + "interface_type_id": { + "type": "integer", + "format": "int32" + }, + "connector_type_id": { + "type": "integer", + "format": "int32" + }, + "mac_addr": { + "type": "string" + }, + "device": { + "$ref": "#/definitions/Device" + }, + "subnet": { + "$ref": "#/definitions/Subnet" + }, + "ip_address": { + "$ref": "#/definitions/IpAddress" + }, + "vlan": { + "$ref": "#/definitions/Vlan" + }, + "direction": { + "$ref": "#/definitions/Direction" + }, + "duplex": { + "$ref": "#/definitions/Duplex" + }, + "interface_speed": { + "$ref": "#/definitions/InterfaceSpeed" + }, + "medium": { + "$ref": "#/definitions/Medium" + }, + "switch_port": { + "$ref": "#/definitions/SwitchPort" + }, + "interface_type": { + "$ref": "#/definitions/InterfaceType" + }, + "connector_type": { + "$ref": "#/definitions/ConnectorType" + }, + "versions": { + "type": "array", + "items": { + "$ref": "#/definitions/Version" + } + } + } + }, + "IpAddress": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "network_address": { + "type": "string" + }, + "int_address": { + "type": "string" + }, + "description": { + "type": "string" + }, + "interface_id": { + "type": "integer", + "format": "int32" + }, + "subnet_id": { + "type": "integer", + "format": "int32" + }, + "created_at": { + "type": "string", + "format": "date-time" + }, + "updated_at": { + "type": "string", + "format": "date-time" + }, + "dns_name": { + "type": "string" + }, + "inet_address": { + "type": "string" + }, + "ip_type": { + "type": "integer", + "format": "int32" + }, + "subnet": { + "$ref": "#/definitions/Subnet" + }, + "interface": { + "$ref": "#/definitions/Interface" + }, + "outgoing_load_balancer_entries": { + "type": "array", + "items": { + "$ref": "#/definitions/LoadBalancerEntry" + } + }, + "incoming_load_balancer_entries": { + "type": "array", + "items": { + "$ref": "#/definitions/LoadBalancerEntry" + } + }, + "versions": { + "type": "array", + "items": { + "$ref": "#/definitions/Version" + } + } + } + }, + "LoadBalancerEntry": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "device_id": { + "type": "integer", + "format": "int32" + }, + "virtual_ip_address_id": { + "type": "integer", + "format": "int32" + }, + "description": { + "type": "string" + }, + "created_at": { + "type": "string", + "format": "date-time" + }, + "updated_at": { + "type": "string", + "format": "date-time" + }, + "physical_ip_id": { + "type": "integer", + "format": "int32" + }, + "device": { + "$ref": "#/definitions/Device" + }, + "virtual_ip_address": { + "$ref": "#/definitions/IpAddress" + }, + "physical_ip": { + "$ref": "#/definitions/IpAddress" + } + } + }, + "Version": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "event": { + "type": "string" + }, + "item_type": { + "type": "string" + }, + "item_id": { + "type": "string" + }, + "whodunnit": { + "type": "string" + }, + "object_changes": { + "type": "string" + } + }, + "description": "Get API Version" + }, + "Duplex": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "name": { + "type": "string" + }, + "created_at": { + "type": "string", + "format": "date-time" + }, + "updated_at": { + "type": "string", + "format": "date-time" + }, + "switch_ports": { + "type": "array", + "items": { + "$ref": "#/definitions/SwitchPort" + } + }, + "interfaces": { + "type": "array", + "items": { + "$ref": "#/definitions/Interface" + } + } + } + }, + "SwitchPort": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "port_number": { + "type": "integer", + "format": "int32" + }, + "speed": { + "type": "integer", + "format": "int32" + }, + "stp": { + "type": "boolean" + }, + "direction": { + "type": "integer", + "format": "int32" + }, + "created_at": { + "type": "string", + "format": "date-time" + }, + "updated_at": { + "type": "string", + "format": "date-time" + }, + "device_id": { + "type": "integer", + "format": "int32" + }, + "duplex_id": { + "type": "integer", + "format": "int32" + }, + "medium_id": { + "type": "integer", + "format": "int32" + }, + "zone_group_id": { + "type": "integer", + "format": "int32" + }, + "blade": { + "type": "string" + }, + "switch_port_type_id": { + "type": "integer", + "format": "int32" + }, + "vlan_id": { + "type": "integer", + "format": "int32" + }, + "notes": { + "type": "string" + }, + "cc_frame_id": { + "type": "integer", + "format": "int32" + }, + "pvlan_edge": { + "type": "integer", + "format": "int32" + }, + "in_use": { + "type": "boolean" + }, + "ether_channel": { + "type": "boolean" + }, + "blade_serial_number": { + "type": "string" + }, + "trunk_id": { + "type": "integer", + "format": "int32" + }, + "stp_port_fast": { + "type": "boolean" + }, + "vpc": { + "type": "integer", + "format": "int32" + }, + "wwn": { + "type": "string" + }, + "connected_mac": { + "type": "string" + }, + "connected_mac_updated_at": { + "type": "string", + "format": "date-time" + }, + "bottom_ru": { + "type": "integer", + "format": "int32" + }, + "supports_kvm": { + "type": "boolean" + }, + "capability": { + "type": "string" + }, + "interface_speed_id": { + "type": "integer", + "format": "int32" + }, + "port_channel": { + "type": "integer", + "format": "int32" + }, + "device": { + "$ref": "#/definitions/Device" + }, + "duplex": { + "$ref": "#/definitions/Duplex" + }, + "medium": { + "$ref": "#/definitions/Medium" + }, + "switch_port_type": { + "$ref": "#/definitions/SwitchPortType" + }, + "interface_speed": { + "$ref": "#/definitions/InterfaceSpeed" + }, + "vlan": { + "$ref": "#/definitions/Vlan" + }, + "interface": { + "$ref": "#/definitions/Interface" + }, + "versions": { + "type": "array", + "items": { + "$ref": "#/definitions/Version" + } + } + } + }, + "Medium": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "name": { + "type": "string" + }, + "created_at": { + "type": "string", + "format": "date-time" + }, + "updated_at": { + "type": "string", + "format": "date-time" + }, + "switch_ports": { + "type": "array", + "items": { + "$ref": "#/definitions/SwitchPort" + } + }, + "interfaces": { + "type": "array", + "items": { + "$ref": "#/definitions/Interface" + } + } + } + }, + "SwitchPortType": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "name": { + "type": "string" + }, + "created_at": { + "type": "string", + "format": "date-time" + }, + "updated_at": { + "type": "string", + "format": "date-time" + }, + "switch_ports": { + "type": "array", + "items": { + "$ref": "#/definitions/SwitchPort" + } + } + } + }, + "InterfaceSpeed": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "name": { + "type": "string" + }, + "created_at": { + "type": "string", + "format": "date-time" + }, + "updated_at": { + "type": "string", + "format": "date-time" + }, + "interfaces": { + "type": "array", + "items": { + "$ref": "#/definitions/Interface" + } + }, + "switch_ports": { + "type": "array", + "items": { + "$ref": "#/definitions/SwitchPort" + } + } + } + }, + "InterfaceType": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "name": { + "type": "string" + }, + "notes": { + "type": "string" + }, + "created_at": { + "type": "string", + "format": "date-time" + }, + "updated_at": { + "type": "string", + "format": "date-time" + }, + "interfaces": { + "type": "array", + "items": { + "$ref": "#/definitions/Interface" + } + } + } + }, + "ConnectorType": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "name": { + "type": "string" + }, + "created_at": { + "type": "string", + "format": "date-time" + }, + "updated_at": { + "type": "string", + "format": "date-time" + }, + "interfaces": { + "type": "array", + "items": { + "$ref": "#/definitions/Interface" + } + } + } + }, + "DataTransaction": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "transactable_type": { + "type": "string" + }, + "transactable_id": { + "type": "integer", + "format": "int32" + }, + "data_cleanup_id": { + "type": "integer", + "format": "int32" + }, + "created_at": { + "type": "string", + "format": "date-time" + }, + "updated_at": { + "type": "string", + "format": "date-time" + }, + "transactions": { + "type": "string" + }, + "data_cleanup": { + "$ref": "#/definitions/DataCleanup" + } + } + }, + "DataCleanup": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "name": { + "type": "string" + }, + "status": { + "type": "integer", + "format": "int32" + }, + "created_at": { + "type": "string", + "format": "date-time" + }, + "updated_at": { + "type": "string", + "format": "date-time" + }, + "data_transactions": { + "type": "array", + "items": { + "$ref": "#/definitions/DataTransaction" + } + } + } + }, + "VlanType": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "name": { + "type": "string" + }, + "created_at": { + "type": "string", + "format": "date-time" + }, + "updated_at": { + "type": "string", + "format": "date-time" + }, + "vlans": { + "type": "array", + "items": { + "$ref": "#/definitions/Vlan" + } + } + } + }, + "DeviceModel": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "name": { + "type": "string" + }, + "created_at": { + "type": "string", + "format": "date-time" + }, + "updated_at": { + "type": "string", + "format": "date-time" + }, + "vendor_name": { + "type": "string" + }, + "manufacturer_name": { + "type": "string" + }, + "integration_class": { + "type": "string" + }, + "status": { + "type": "integer", + "format": "int32" + }, + "devices": { + "type": "array", + "items": { + "$ref": "#/definitions/Device" + } + }, + "device_types": { + "type": "array", + "items": { + "$ref": "#/definitions/DeviceType" + } + }, + "default_interfaces": { + "type": "array", + "items": { + "$ref": "#/definitions/DefaultInterface" + } + } + } + }, + "DeviceType": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "name": { + "type": "string" + }, + "networkable": { + "type": "boolean" + }, + "routable": { + "type": "boolean" + }, + "interfaceable": { + "type": "boolean" + }, + "switchable": { + "type": "boolean" + }, + "has_switch_ports": { + "type": "boolean" + }, + "rackable": { + "type": "boolean" + }, + "virtual_client": { + "type": "boolean" + }, + "virtual_host": { + "type": "boolean" + }, + "created_at": { + "type": "string", + "format": "date-time" + }, + "updated_at": { + "type": "string", + "format": "date-time" + }, + "device_category_id": { + "type": "integer", + "format": "int32" + }, + "has_blades": { + "type": "boolean" + }, + "is_blade": { + "type": "boolean" + }, + "is_load_balancer": { + "type": "boolean" + }, + "is_patch_panel": { + "type": "boolean" + }, + "extends_switch": { + "type": "boolean" + }, + "esmt_device_category_id": { + "type": "integer", + "format": "int32" + }, + "esmt_device_type_id": { + "type": "integer", + "format": "int32" + }, + "esmt_device_class_id": { + "type": "integer", + "format": "int32" + }, + "devices": { + "type": "array", + "items": { + "$ref": "#/definitions/Device" + } + }, + "device_models": { + "type": "array", + "items": { + "$ref": "#/definitions/DeviceModel" + } + }, + "esmt_device_class": { + "$ref": "#/definitions/EsmtDeviceClass" + }, + "esmt_device_type": { + "$ref": "#/definitions/EsmtDeviceType" + }, + "esmt_device_category": { + "$ref": "#/definitions/EsmtDeviceCategory" + }, + "device_category": { + "$ref": "#/definitions/DeviceCategory" + } + } + }, + "EsmtDeviceClass": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "name": { + "type": "string" + }, + "created_at": { + "type": "string", + "format": "date-time" + }, + "updated_at": { + "type": "string", + "format": "date-time" + }, + "device_types": { + "type": "array", + "items": { + "$ref": "#/definitions/DeviceType" + } + } + } + }, + "EsmtDeviceType": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "name": { + "type": "string" + }, + "created_at": { + "type": "string", + "format": "date-time" + }, + "updated_at": { + "type": "string", + "format": "date-time" + }, + "device_types": { + "type": "array", + "items": { + "$ref": "#/definitions/DeviceType" + } + } + } + }, + "EsmtDeviceCategory": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "name": { + "type": "string" + }, + "created_at": { + "type": "string", + "format": "date-time" + }, + "updated_at": { + "type": "string", + "format": "date-time" + }, + "device_categories": { + "type": "array", + "items": { + "$ref": "#/definitions/DeviceCategory" + } + }, + "device_types": { + "type": "array", + "items": { + "$ref": "#/definitions/DeviceType" + } + } + } + }, + "DeviceCategory": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "name": { + "type": "string" + }, + "interfaceable": { + "type": "boolean" + }, + "networkable": { + "type": "boolean" + }, + "routable": { + "type": "boolean" + }, + "switchable": { + "type": "boolean" + }, + "has_switch_ports": { + "type": "boolean" + }, + "rackable": { + "type": "boolean" + }, + "virtual_host": { + "type": "boolean" + }, + "virtual_client": { + "type": "boolean" + }, + "created_at": { + "type": "string", + "format": "date-time" + }, + "updated_at": { + "type": "string", + "format": "date-time" + }, + "has_blades": { + "type": "boolean" + }, + "is_blade": { + "type": "boolean" + }, + "is_load_balancer": { + "type": "boolean" + }, + "is_patch_panel": { + "type": "boolean" + }, + "extends_switch": { + "type": "boolean" + }, + "device_types": { + "type": "array", + "items": { + "$ref": "#/definitions/DeviceType" + } + }, + "esmt_device_type": { + "$ref": "#/definitions/EsmtDeviceType" + }, + "esmt_device_category": { + "$ref": "#/definitions/EsmtDeviceCategory" + } + } + }, + "DefaultInterface": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "name": { + "type": "string" + }, + "device_model_id": { + "type": "integer", + "format": "int32" + }, + "direction": { + "type": "integer", + "format": "int32" + }, + "speed": { + "type": "integer", + "format": "int32" + }, + "require_ip": { + "type": "boolean" + }, + "require_switch_port": { + "type": "boolean" + }, + "require_default_gateway": { + "type": "boolean" + }, + "interface_type": { + "type": "integer", + "format": "int32" + }, + "notes": { + "type": "string" + }, + "created_at": { + "type": "string", + "format": "date-time" + }, + "updated_at": { + "type": "string", + "format": "date-time" + }, + "device_model": { + "$ref": "#/definitions/DeviceModel" + } + } + }, + "Project": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "name": { + "type": "string" + }, + "code": { + "type": "string" + }, + "system_id": { + "type": "integer", + "format": "int32" + }, + "created_at": { + "type": "string", + "format": "date-time" + }, + "updated_at": { + "type": "string", + "format": "date-time" + }, + "ciid": { + "type": "string" + }, + "instance_id": { + "type": "string" + }, + "reconciliation_identity": { + "type": "string" + }, + "workbook_location": { + "type": "string" + }, + "device_status_id": { + "type": "integer", + "format": "int32" + }, + "device_status_reason_id": { + "type": "integer", + "format": "int32" + }, + "event_logs": { + "type": "array", + "items": { + "$ref": "#/definitions/EventLog" + } + }, + "sync_status": { + "$ref": "#/definitions/SyncStatus" + }, + "device_status": { + "$ref": "#/definitions/DeviceStatus" + }, + "device_status_reason": { + "$ref": "#/definitions/DeviceStatusReason" + }, + "devices": { + "type": "array", + "items": { + "$ref": "#/definitions/Device" + } + }, + "system": { + "$ref": "#/definitions/System" + } + } + }, + "System": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "name": { + "type": "string" + }, + "description": { + "type": "string" + }, + "created_at": { + "type": "string", + "format": "date-time" + }, + "updated_at": { + "type": "string", + "format": "date-time" + }, + "ciid": { + "type": "string" + }, + "instance_id": { + "type": "string" + }, + "reconciliation_identity": { + "type": "string" + }, + "device_status_id": { + "type": "integer", + "format": "int32" + }, + "device_status_reason_id": { + "type": "integer", + "format": "int32" + }, + "event_logs": { + "type": "array", + "items": { + "$ref": "#/definitions/EventLog" + } + }, + "sync_status": { + "$ref": "#/definitions/SyncStatus" + }, + "device_status": { + "$ref": "#/definitions/DeviceStatus" + }, + "device_status_reason": { + "$ref": "#/definitions/DeviceStatusReason" + }, + "projects": { + "type": "array", + "items": { + "$ref": "#/definitions/Project" + } + } + } + }, + "ApplicationEnvironment": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "name": { + "type": "string" + }, + "ciid": { + "type": "string" + }, + "impact_scale": { + "type": "integer", + "format": "int32" + }, + "created_at": { + "type": "string", + "format": "date-time" + }, + "updated_at": { + "type": "string", + "format": "date-time" + }, + "instance_id": { + "type": "string" + }, + "reconciliation_identity": { + "type": "string" + }, + "device_status_id": { + "type": "integer", + "format": "int32" + }, + "device_status_reason_id": { + "type": "integer", + "format": "int32" + }, + "event_logs": { + "type": "array", + "items": { + "$ref": "#/definitions/EventLog" + } + }, + "sync_status": { + "$ref": "#/definitions/SyncStatus" + }, + "device_status": { + "$ref": "#/definitions/DeviceStatus" + }, + "device_status_reason": { + "$ref": "#/definitions/DeviceStatusReason" + }, + "devices": { + "type": "array", + "items": { + "$ref": "#/definitions/Device" + } + } + } + }, + "OperatingSystem": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "name": { + "type": "string" + }, + "ciid": { + "type": "string" + }, + "device_status_id": { + "type": "integer", + "format": "int32" + }, + "device_status_reason_id": { + "type": "integer", + "format": "int32" + }, + "reconciliation_identity": { + "type": "string" + }, + "created_at": { + "type": "string", + "format": "date-time" + }, + "updated_at": { + "type": "string", + "format": "date-time" + }, + "instance_id": { + "type": "string" + }, + "event_logs": { + "type": "array", + "items": { + "$ref": "#/definitions/EventLog" + } + }, + "sync_status": { + "$ref": "#/definitions/SyncStatus" + }, + "device_status": { + "$ref": "#/definitions/DeviceStatus" + }, + "device_status_reason": { + "$ref": "#/definitions/DeviceStatusReason" + }, + "devices": { + "type": "array", + "items": { + "$ref": "#/definitions/Device" + } + } + } + }, + "HostNameReservation": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "host_name": { + "type": "string" + }, + "created_at": { + "type": "string", + "format": "date-time" + }, + "updated_at": { + "type": "string", + "format": "date-time" + }, + "device_id": { + "type": "integer", + "format": "int32" + }, + "device": { + "$ref": "#/definitions/Device" + } + } + }, + "NatEntry": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "in_ip_id": { + "type": "integer", + "format": "int32" + }, + "out_ip_id": { + "type": "integer", + "format": "int32" + }, + "device_id": { + "type": "integer", + "format": "int32" + }, + "description": { + "type": "string" + }, + "created_at": { + "type": "string", + "format": "date-time" + }, + "updated_at": { + "type": "string", + "format": "date-time" + }, + "device": { + "$ref": "#/definitions/Device" + }, + "in_ip": { + "$ref": "#/definitions/IpAddress" + }, + "out_ip": { + "$ref": "#/definitions/IpAddress" + } + } + }, + "VmHostPool": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "ciid": { + "type": "string" + }, + "name": { + "type": "string" + }, + "created_at": { + "type": "string", + "format": "date-time" + }, + "updated_at": { + "type": "string", + "format": "date-time" + }, + "hosts": { + "type": "array", + "items": { + "$ref": "#/definitions/Device" + } + }, + "clients": { + "type": "array", + "items": { + "$ref": "#/definitions/Device" + } + } + } + }, + "SubnetAssignment": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "device_id": { + "type": "integer", + "format": "int32" + }, + "subnet_id": { + "type": "integer", + "format": "int32" + }, + "assigns_vips": { + "type": "boolean" + }, + "assigns_physical_ips": { + "type": "boolean" + }, + "created_at": { + "type": "string", + "format": "date-time" + }, + "updated_at": { + "type": "string", + "format": "date-time" + }, + "device": { + "$ref": "#/definitions/Device" + }, + "subnet": { + "$ref": "#/definitions/Subnet" + } + } + }, + "NmdbQueryError": { + "type": "object", + "properties": { + "message": { + "type": "string" + }, + "filters": { + "type": "string" + }, + "rels": { + "type": "string" + } + }, + "description": "GET Nmdb::Device Object." + }, + "postV2Devices": { + "type": "object", + "properties": { + "body": { + "type": "object", + "properties": { + "ciid": { + "type": "string" + }, + "host_name": { + "type": "string" + }, + "description": { + "type": "string" + }, + "zone_id": { + "type": "integer", + "format": "int32" + }, + "project_id": { + "type": "integer", + "format": "int32" + }, + "device_model_id": { + "type": "integer", + "format": "int32" + }, + "rack_id": { + "type": "integer", + "format": "int32" + }, + "device_status_id": { + "type": "integer", + "format": "int32" + }, + "device_status_reason_id": { + "type": "integer", + "format": "int32" + }, + "asset_tag": { + "type": "string" + }, + "reconciliation_identity": { + "type": "string" + }, + "serial_number": { + "type": "string" + }, + "application_environment_id": { + "type": "integer", + "format": "int32" + }, + "pod_id": { + "type": "integer", + "format": "int32" + }, + "vm_capacity": { + "type": "integer", + "format": "int32" + }, + "switch_domain_id": { + "type": "integer", + "format": "int32" + }, + "blade_slot": { + "type": "integer", + "format": "int32" + }, + "blade_slots_required": { + "type": "integer", + "format": "int32" + }, + "blade_chassis_id": { + "type": "integer", + "format": "int32" + }, + "virtual_host_id": { + "type": "integer", + "format": "int32" + }, + "physical_host_id": { + "type": "integer", + "format": "int32" + }, + "blade_capacity": { + "type": "integer", + "format": "int32" + }, + "device_type_id": { + "type": "integer", + "format": "int32" + }, + "ru_required": { + "type": "integer", + "format": "int32" + }, + "primary_device_id": { + "type": "integer", + "format": "int32" + }, + "instance_id": { + "type": "string" + }, + "operating_system_id": { + "type": "integer", + "format": "int32" + }, + "workbook_version": { + "type": "string" + }, + "virtualized_on_vm_host_pool_id": { + "type": "integer", + "format": "int32" + }, + "contained_in_vm_host_pool_id": { + "type": "integer", + "format": "int32" + }, + "a_or_b": { + "type": "integer", + "format": "int32" + }, + "bottom_ru": { + "type": "integer", + "format": "int32" + }, + "host_name_reservation_id": { + "type": "integer", + "format": "int32" + }, + "interfaces_attributes": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "mac_address": { + "type": "string" + }, + "name": { + "type": "string" + }, + "device_id": { + "type": "integer", + "format": "int32" + }, + "created_at": { + "type": "string", + "format": "date-time" + }, + "updated_at": { + "type": "string", + "format": "date-time" + }, + "require_ip": { + "type": "boolean" + }, + "require_switch_port": { + "type": "boolean" + }, + "require_default_gateway": { + "type": "boolean" + }, + "notes": { + "type": "string" + }, + "media": { + "type": "integer", + "format": "int32" + }, + "vlan_direction_id": { + "type": "integer", + "format": "int32" + }, + "interface_speed_id": { + "type": "integer", + "format": "int32" + }, + "vlan_id": { + "type": "integer", + "format": "int32" + }, + "subnet_id": { + "type": "integer", + "format": "int32" + }, + "direction_id": { + "type": "integer", + "format": "int32" + }, + "duplex_id": { + "type": "integer", + "format": "int32" + }, + "medium_id": { + "type": "integer", + "format": "int32" + }, + "switch_port_id": { + "type": "integer", + "format": "int32" + }, + "pci_slot": { + "type": "string" + }, + "a_or_b": { + "type": "integer", + "format": "int32" + }, + "require_route_for_management": { + "type": "boolean" + }, + "require_route_for_getronics": { + "type": "boolean" + }, + "default_gateway_id": { + "type": "integer", + "format": "int32" + }, + "static_routes": { + "type": "string" + }, + "interface_type_id": { + "type": "integer", + "format": "int32" + }, + "connector_type_id": { + "type": "integer", + "format": "int32" + }, + "mac_addr": { + "type": "string" + }, + "ip_address_id": { + "type": "integer", + "format": "int32" + }, + "_destroy": { + "type": "boolean" + } + } + } + }, + "switch_ports_attributes": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "port_number": { + "type": "integer", + "format": "int32" + }, + "speed": { + "type": "integer", + "format": "int32" + }, + "stp": { + "type": "boolean" + }, + "direction": { + "type": "integer", + "format": "int32" + }, + "created_at": { + "type": "string", + "format": "date-time" + }, + "updated_at": { + "type": "string", + "format": "date-time" + }, + "device_id": { + "type": "integer", + "format": "int32" + }, + "duplex_id": { + "type": "integer", + "format": "int32" + }, + "medium_id": { + "type": "integer", + "format": "int32" + }, + "zone_group_id": { + "type": "integer", + "format": "int32" + }, + "blade": { + "type": "string" + }, + "switch_port_type_id": { + "type": "integer", + "format": "int32" + }, + "vlan_id": { + "type": "integer", + "format": "int32" + }, + "notes": { + "type": "string" + }, + "cc_frame_id": { + "type": "integer", + "format": "int32" + }, + "pvlan_edge": { + "type": "integer", + "format": "int32" + }, + "in_use": { + "type": "boolean" + }, + "ether_channel": { + "type": "boolean" + }, + "blade_serial_number": { + "type": "string" + }, + "trunk_id": { + "type": "integer", + "format": "int32" + }, + "stp_port_fast": { + "type": "boolean" + }, + "vpc": { + "type": "integer", + "format": "int32" + }, + "wwn": { + "type": "string" + }, + "connected_mac": { + "type": "string" + }, + "connected_mac_updated_at": { + "type": "string", + "format": "date-time" + }, + "bottom_ru": { + "type": "integer", + "format": "int32" + }, + "supports_kvm": { + "type": "boolean" + }, + "capability": { + "type": "string" + }, + "interface_speed_id": { + "type": "integer", + "format": "int32" + }, + "port_channel": { + "type": "integer", + "format": "int32" + }, + "_destroy": { + "type": "boolean" + } + } + } + }, + "nat_entries_attributes": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "in_ip_id": { + "type": "integer", + "format": "int32" + }, + "out_ip_id": { + "type": "integer", + "format": "int32" + }, + "device_id": { + "type": "integer", + "format": "int32" + }, + "description": { + "type": "string" + }, + "created_at": { + "type": "string", + "format": "date-time" + }, + "updated_at": { + "type": "string", + "format": "date-time" + }, + "_destroy": { + "type": "boolean" + } + } + } + }, + "load_balancer_entries_attributes": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "device_id": { + "type": "integer", + "format": "int32" + }, + "virtual_ip_address_id": { + "type": "integer", + "format": "int32" + }, + "description": { + "type": "string" + }, + "created_at": { + "type": "string", + "format": "date-time" + }, + "updated_at": { + "type": "string", + "format": "date-time" + }, + "physical_ip_id": { + "type": "integer", + "format": "int32" + }, + "_destroy": { + "type": "boolean" + } + } + } + }, + "subnet_assignments_attributes": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "device_id": { + "type": "integer", + "format": "int32" + }, + "subnet_id": { + "type": "integer", + "format": "int32" + }, + "assigns_vips": { + "type": "boolean" + }, + "assigns_physical_ips": { + "type": "boolean" + }, + "created_at": { + "type": "string", + "format": "date-time" + }, + "updated_at": { + "type": "string", + "format": "date-time" + }, + "_destroy": { + "type": "boolean" + } + } + } + } + } + } + }, + "required": [ + "body" + ], + "description": "Create Nmdb::Device Object." + }, + "putV2Devices": { + "type": "object", + "properties": { + "body": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "ciid": { + "type": "string" + }, + "host_name": { + "type": "string" + }, + "description": { + "type": "string" + }, + "zone_id": { + "type": "integer", + "format": "int32" + }, + "project_id": { + "type": "integer", + "format": "int32" + }, + "device_model_id": { + "type": "integer", + "format": "int32" + }, + "rack_id": { + "type": "integer", + "format": "int32" + }, + "device_status_id": { + "type": "integer", + "format": "int32" + }, + "device_status_reason_id": { + "type": "integer", + "format": "int32" + }, + "asset_tag": { + "type": "string" + }, + "reconciliation_identity": { + "type": "string" + }, + "serial_number": { + "type": "string" + }, + "application_environment_id": { + "type": "integer", + "format": "int32" + }, + "pod_id": { + "type": "integer", + "format": "int32" + }, + "vm_capacity": { + "type": "integer", + "format": "int32" + }, + "switch_domain_id": { + "type": "integer", + "format": "int32" + }, + "blade_slot": { + "type": "integer", + "format": "int32" + }, + "blade_slots_required": { + "type": "integer", + "format": "int32" + }, + "blade_chassis_id": { + "type": "integer", + "format": "int32" + }, + "virtual_host_id": { + "type": "integer", + "format": "int32" + }, + "physical_host_id": { + "type": "integer", + "format": "int32" + }, + "blade_capacity": { + "type": "integer", + "format": "int32" + }, + "device_type_id": { + "type": "integer", + "format": "int32" + }, + "ru_required": { + "type": "integer", + "format": "int32" + }, + "primary_device_id": { + "type": "integer", + "format": "int32" + }, + "instance_id": { + "type": "string" + }, + "operating_system_id": { + "type": "integer", + "format": "int32" + }, + "workbook_version": { + "type": "string" + }, + "virtualized_on_vm_host_pool_id": { + "type": "integer", + "format": "int32" + }, + "contained_in_vm_host_pool_id": { + "type": "integer", + "format": "int32" + }, + "a_or_b": { + "type": "integer", + "format": "int32" + }, + "bottom_ru": { + "type": "integer", + "format": "int32" + }, + "interfaces_attributes": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "mac_address": { + "type": "string" + }, + "name": { + "type": "string" + }, + "device_id": { + "type": "integer", + "format": "int32" + }, + "created_at": { + "type": "string", + "format": "date-time" + }, + "updated_at": { + "type": "string", + "format": "date-time" + }, + "require_ip": { + "type": "boolean" + }, + "require_switch_port": { + "type": "boolean" + }, + "require_default_gateway": { + "type": "boolean" + }, + "notes": { + "type": "string" + }, + "media": { + "type": "integer", + "format": "int32" + }, + "vlan_direction_id": { + "type": "integer", + "format": "int32" + }, + "interface_speed_id": { + "type": "integer", + "format": "int32" + }, + "vlan_id": { + "type": "integer", + "format": "int32" + }, + "subnet_id": { + "type": "integer", + "format": "int32" + }, + "direction_id": { + "type": "integer", + "format": "int32" + }, + "duplex_id": { + "type": "integer", + "format": "int32" + }, + "medium_id": { + "type": "integer", + "format": "int32" + }, + "switch_port_id": { + "type": "integer", + "format": "int32" + }, + "pci_slot": { + "type": "string" + }, + "a_or_b": { + "type": "integer", + "format": "int32" + }, + "require_route_for_management": { + "type": "boolean" + }, + "require_route_for_getronics": { + "type": "boolean" + }, + "default_gateway_id": { + "type": "integer", + "format": "int32" + }, + "static_routes": { + "type": "string" + }, + "interface_type_id": { + "type": "integer", + "format": "int32" + }, + "connector_type_id": { + "type": "integer", + "format": "int32" + }, + "mac_addr": { + "type": "string" + }, + "ip_address_id": { + "type": "integer", + "format": "int32" + }, + "_destroy": { + "type": "boolean" + } + } + } + }, + "switch_ports_attributes": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "port_number": { + "type": "integer", + "format": "int32" + }, + "speed": { + "type": "integer", + "format": "int32" + }, + "stp": { + "type": "boolean" + }, + "direction": { + "type": "integer", + "format": "int32" + }, + "created_at": { + "type": "string", + "format": "date-time" + }, + "updated_at": { + "type": "string", + "format": "date-time" + }, + "device_id": { + "type": "integer", + "format": "int32" + }, + "duplex_id": { + "type": "integer", + "format": "int32" + }, + "medium_id": { + "type": "integer", + "format": "int32" + }, + "zone_group_id": { + "type": "integer", + "format": "int32" + }, + "blade": { + "type": "string" + }, + "switch_port_type_id": { + "type": "integer", + "format": "int32" + }, + "vlan_id": { + "type": "integer", + "format": "int32" + }, + "notes": { + "type": "string" + }, + "cc_frame_id": { + "type": "integer", + "format": "int32" + }, + "pvlan_edge": { + "type": "integer", + "format": "int32" + }, + "in_use": { + "type": "boolean" + }, + "ether_channel": { + "type": "boolean" + }, + "blade_serial_number": { + "type": "string" + }, + "trunk_id": { + "type": "integer", + "format": "int32" + }, + "stp_port_fast": { + "type": "boolean" + }, + "vpc": { + "type": "integer", + "format": "int32" + }, + "wwn": { + "type": "string" + }, + "connected_mac": { + "type": "string" + }, + "connected_mac_updated_at": { + "type": "string", + "format": "date-time" + }, + "bottom_ru": { + "type": "integer", + "format": "int32" + }, + "supports_kvm": { + "type": "boolean" + }, + "capability": { + "type": "string" + }, + "interface_speed_id": { + "type": "integer", + "format": "int32" + }, + "port_channel": { + "type": "integer", + "format": "int32" + }, + "_destroy": { + "type": "boolean" + } + } + } + }, + "nat_entries_attributes": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "in_ip_id": { + "type": "integer", + "format": "int32" + }, + "out_ip_id": { + "type": "integer", + "format": "int32" + }, + "device_id": { + "type": "integer", + "format": "int32" + }, + "description": { + "type": "string" + }, + "created_at": { + "type": "string", + "format": "date-time" + }, + "updated_at": { + "type": "string", + "format": "date-time" + }, + "_destroy": { + "type": "boolean" + } + } + } + }, + "load_balancer_entries_attributes": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "device_id": { + "type": "integer", + "format": "int32" + }, + "virtual_ip_address_id": { + "type": "integer", + "format": "int32" + }, + "description": { + "type": "string" + }, + "created_at": { + "type": "string", + "format": "date-time" + }, + "updated_at": { + "type": "string", + "format": "date-time" + }, + "physical_ip_id": { + "type": "integer", + "format": "int32" + }, + "_destroy": { + "type": "boolean" + } + } + } + }, + "subnet_assignments_attributes": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "device_id": { + "type": "integer", + "format": "int32" + }, + "subnet_id": { + "type": "integer", + "format": "int32" + }, + "assigns_vips": { + "type": "boolean" + }, + "assigns_physical_ips": { + "type": "boolean" + }, + "created_at": { + "type": "string", + "format": "date-time" + }, + "updated_at": { + "type": "string", + "format": "date-time" + }, + "_destroy": { + "type": "boolean" + } + } + } + } + } + } + }, + "required": [ + "body" + ], + "description": "Update Nmdb::Device Object." + } + } +} diff --git a/fixtures/expansion/circular-minimal.json b/fixtures/expansion/circular-minimal.json new file mode 100644 index 0000000..56a066e --- /dev/null +++ b/fixtures/expansion/circular-minimal.json @@ -0,0 +1,58 @@ +{ + "swagger": "2.0", + "info": { + "version": "0.0.1" + }, + "basePath": "/", + "paths": { + "/cycles": { + "get": { + "responses": { + "200": { + "description": "ok", + "schema": { + "$ref": "#/definitions/node0" + } + } + } + } + } + }, + "definitions": { + "node0": { + "type": "object", + "properties": { + "p00": { + "$ref": "#/definitions/node1" + }, + "p01": { + "$ref": "#/definitions/node3" + } + } + }, + "node1": { + "type": "object", + "properties": { + "p1": { + "$ref": "#/definitions/node2" + } + } + }, + "node2": { + "type": "object", + "properties": { + "p2": { + "$ref": "#/definitions/node0" + } + } + }, + "node3": { + "type": "object", + "properties": { + "p3": { + "$ref": "#/definitions/node1" + } + } + } + } +} diff --git a/fixtures/expansion/circularSpec2.json b/fixtures/expansion/circularSpec2.json new file mode 100644 index 0000000..e535418 --- /dev/null +++ b/fixtures/expansion/circularSpec2.json @@ -0,0 +1,330 @@ +{ + "swagger": "2.0", + "info": { + "title": "swagger.yaml for investigating an issue with spec.expandSchema", + "version": "0.0.1", + "description": "expander.go test for issue analysis, the spec derived from ODataWebV3.Northwind.Model and simplified for the analysis" + }, + "schemes": [ + "http" + ], + "host": "localhost", + "basePath": "/modified_from_Northwind.svc", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "paths": { + "/Employees": { + "get": { + "summary": "Get entities from Employees", + "responses": { + "200": { + "description": "Retrieved entities", + "schema": { + "title": "Collection of Employee", + "type": "object", + "properties": { + "value": { + "type": "array", + "items": { + "$ref": "#/definitions/Employee" + } + } + } + } + }, + "default": { + "$ref": "#/responses/error" + } + } + } + } + }, + "definitions": { + "Category": { + "type": "object", + "properties": { + "CategoryID": { + "type": "integer", + "format": "int32" + }, + "CategoryName": { + "type": "string", + "maxLength": 15 + }, + "Products": { + "type": "array", + "items": { + "$ref": "#/definitions/Product" + } + } + }, + "title": "Category" + }, + "CustomerDemographic": { + "type": "object", + "properties": { + "CustomerTypeID": { + "type": "string", + "maxLength": 10 + }, + "CustomerDesc": { + "type": "string", + "example": "string" + }, + "Customers": { + "type": "array", + "items": { + "$ref": "#/definitions/Customer" + } + } + }, + "title": "CustomerDemographic" + }, + "Customer": { + "type": "object", + "properties": { + "CustomerID": { + "type": "string", + "maxLength": 5 + }, + "CompanyName": { + "type": "string", + "maxLength": 40 + }, + "Orders": { + "type": "array", + "items": { + "$ref": "#/definitions/Order" + } + }, + "CustomerDemographics": { + "type": "array", + "items": { + "$ref": "#/definitions/CustomerDemographic" + } + } + }, + "title": "Customer" + }, + "Employee": { + "type": "object", + "properties": { + "EmployeeID": { + "type": "integer", + "format": "int32" + }, + "LastName": { + "type": "string", + "maxLength": 20 + }, + "FirstName": { + "type": "string", + "maxLength": 10 + }, + "Employees1": { + "type": "array", + "items": { + "$ref": "#/definitions/Employee" + } + }, + "Employee1": { + "$ref": "#/definitions/Employee" + }, + "Orders": { + "type": "array", + "items": { + "$ref": "#/definitions/Order" + } + }, + "Territories": { + "type": "array", + "items": { + "$ref": "#/definitions/Territory" + } + } + }, + "title": "Employee" + }, + "Order_Detail": { + "type": "object", + "properties": { + "OrderID": { + "type": "integer", + "format": "int32" + }, + "ProductID": { + "type": "integer", + "format": "int32" + }, + "UnitPrice": { + "type": "number", + "format": "decimal", + "multipleOf": 0.0001 + }, + "Quantity": { + "type": "integer", + "format": "int16" + }, + "Order": { + "$ref": "#/definitions/Order" + }, + "Product": { + "$ref": "#/definitions/Product" + } + }, + "title": "Order_Detail" + }, + "Order": { + "type": "object", + "properties": { + "OrderID": { + "type": "integer", + "format": "int32" + }, + "CustomerID": { + "type": "string", + "maxLength": 5, + "example": "string" + }, + "Customer": { + "$ref": "#/definitions/Customer" + }, + "Employee": { + "$ref": "#/definitions/Employee" + }, + "Order_Details": { + "type": "array", + "items": { + "$ref": "#/definitions/Order_Detail" + } + }, + "Shipper": { + "$ref": "#/definitions/Shipper" + } + }, + "title": "Order" + }, + "Product": { + "type": "object", + "properties": { + "ProductID": { + "type": "integer", + "format": "int32" + }, + "ProductName": { + "type": "string", + "maxLength": 40 + }, + "Category": { + "$ref": "#/definitions/Category" + }, + "Order_Details": { + "type": "array", + "items": { + "$ref": "#/definitions/Order_Detail" + } + }, + "Supplier": { + "$ref": "#/definitions/Supplier" + } + }, + "title": "Product" + }, + "Region": { + "type": "object", + "properties": { + "RegionID": { + "type": "integer", + "format": "int32" + }, + "RegionDescription": { + "type": "string", + "maxLength": 50 + }, + "Territories": { + "type": "array", + "items": { + "$ref": "#/definitions/Territory" + } + } + }, + "title": "Region" + }, + "Shipper": { + "type": "object", + "properties": { + "ShipperID": { + "type": "integer", + "format": "int32" + }, + "CompanyName": { + "type": "string", + "maxLength": 40 + }, + "Orders": { + "type": "array", + "items": { + "$ref": "#/definitions/Order" + } + } + }, + "title": "Shipper" + }, + "Supplier": { + "type": "object", + "properties": { + "SupplierID": { + "type": "integer", + "format": "int32" + }, + "CompanyName": { + "type": "string", + "maxLength": 40 + }, + "Products": { + "type": "array", + "items": { + "$ref": "#/definitions/Product" + } + } + }, + "title": "Supplier" + }, + "Territory": { + "type": "object", + "properties": { + "TerritoryID": { + "type": "string", + "maxLength": 20 + }, + "TerritoryDescription": { + "type": "string", + "maxLength": 50 + }, + "RegionID": { + "type": "integer", + "format": "int32" + }, + "Region": { + "$ref": "#/definitions/Region" + }, + "Employees": { + "type": "array", + "items": { + "$ref": "#/definitions/Employee" + } + } + }, + "title": "Territory" + } + }, + "responses": { + "error": { + "description": "Error" + } + } +}