netbox-community / netbox

The premier source of truth powering network automation. Open source under Apache 2. Public demo: https://demo.netbox.dev
http://netboxlabs.com/oss/netbox/
Apache License 2.0
15.49k stars 2.52k forks source link

API call to create new prefix fails #4293

Closed ross-alexander closed 4 years ago

ross-alexander commented 4 years ago

Environment

Steps to Reproduce

  1. Using shell script wrapper to call curl to create new prefix using POST to /api/ipam/prefixes/ with data '{"prefix":"10.147.8.0/22", "status":"container"}'
KEY="REDACTED"
BASE="http://agp-sog-p-nbox1.agp.local:8001/api"

curl --resolve agp-sog-p-nbox1.agp.local:8001:127.0.0.1 -v -H "Authorization: Token $KEY" -H "Accept: application/json" -X POST --data '{"prefix":"10.147.8.0/22", "status":"container"}' $BASE/ipam/prefixes/
  1. Run script with output from curl
* Added agp-sog-p-nbox1.agp.local:8001:127.0.0.1 to DNS cache
* Hostname agp-sog-p-nbox1.agp.local was found in DNS cache
*   Trying 127.0.0.1...
* TCP_NODELAY set
* Connected to agp-sog-p-nbox1.agp.local (127.0.0.1) port 8001 (#0)
> POST /api/ipam/prefixes/ HTTP/1.1
> Host: agp-sog-p-nbox1.agp.local:8001
> User-Agent: curl/7.61.1
> Authorization: Token dd05f773146fcedcf1083afdc524793f07a28460
> Accept: application/json
> Content-Length: 48
> Content-Type: application/x-www-form-urlencoded
>
* upload completely sent off: 48 out of 48 bytes
< HTTP/1.1 400 Bad Request
< Server: gunicorn/20.0.4
< Date: Thu, 27 Feb 2020 11:52:45 GMT
< Connection: keep-alive
< Content-Type: application/json
< Vary: Accept, Cookie, Origin
< Allow: GET, POST, HEAD, OPTIONS
< API-Version: 2.7
< X-Frame-Options: SAMEORIGIN
< Content-Length: 38
<
* Connection #0 to host agp-sog-p-nbox1.agp.local left intact
{"prefix":["This field is required."]}

Expected Behavior

Create new prefix (from the API documentation only the field "prefix" is required.

Observed Behavior

{"prefix":["This field is required."]}

I have a separate 2.7.8 with python 3.8.1 I get the following debug.

+ curl --resolve exile.hepazulian.net:8001:127.0.0.1 -v -H 'Authorization: Token ceda9bc3a5d14bf8df32f4eb6a94a96d7b38753a' -H 'Accept: application/json' -X POST --data @post.js http://exile.hepazulian.net:8001/api/ipam/prefixes/
Note: Unnecessary use of -X or --request, POST is already inferred.
* Added exile.hepazulian.net:8001:127.0.0.1 to DNS cache
* Hostname exile.hepazulian.net was found in DNS cache
*   Trying 127.0.0.1...
* TCP_NODELAY set
* Connected to exile.hepazulian.net (127.0.0.1) port 8001 (#0)
> POST /api/ipam/prefixes/ HTTP/1.1
> Host: exile.hepazulian.net:8001
> User-Agent: curl/7.63.0
> Authorization: Token ceda9bc3a5d14bf8df32f4eb6a94a96d7b38753a
> Accept: application/json
> Content-Length: 57
> Content-Type: application/x-www-form-urlencoded
>
* upload completely sent off: 57 out of 57 bytes
< HTTP/1.1 500 Internal Server Error
< Server: gunicorn/20.0.4
< Date: Thu, 27 Feb 2020 12:43:57 GMT
< Connection: keep-alive
< Content-Type: text/plain; charset=utf-8
< API-Version: 2.7
< X-Frame-Options: SAMEORIGIN
< Content-Length: 20663
< Vary: Cookie, Origin
<
AttributeError at /api/ipam/prefixes/
This QueryDict instance is immutable

Request Method: POST
Request URL: http://exile.hepazulian.net:8001/api/ipam/prefixes/
Django Version: 2.2.10
Python Executable: /usr/bin/python3
Python Version: 3.8.1
Python Path: ['/opt/netbox/netbox', '/opt/netbox-2.7.8', '/usr/bin', '/usr/lib/python38.zip', '/usr/lib/python3.8', '/usr/lib/python3.8/lib-dynload', '/usr/lib/python3.8/site-packages', '/usr/lib/python3.8/site-packages/http_parser-0.8.3-py3.8-linux-x86_64.egg']
Server time: Thu, 27 Feb 2020 12:43:57 +0000
Installed Applications:
['django.contrib.admin',
 'django.contrib.auth',
 'django.contrib.contenttypes',
 'django.contrib.sessions',
 'django.contrib.messages',
 'django.contrib.staticfiles',
 'django.contrib.humanize',
 'cacheops',
 'corsheaders',
 'debug_toolbar',
 'django_filters',
 'django_rq',
 'django_tables2',
 'django_prometheus',
 'mptt',
 'rest_framework',
 'taggit',
 'taggit_serializer',
 'timezone_field',
 'circuits',
 'dcim',
 'ipam',
 'extras',
 'secrets',
 'tenancy',
 'users',
 'utilities',
 'virtualization',
 'drf_yasg']
Installed Middleware:
('debug_toolbar.middleware.DebugToolbarMiddleware',
 'django_prometheus.middleware.PrometheusBeforeMiddleware',
 'corsheaders.middleware.CorsMiddleware',
 'django.contrib.sessions.middleware.SessionMiddleware',
 'django.middleware.common.CommonMiddleware',
 'django.middleware.csrf.CsrfViewMiddleware',
 'django.contrib.auth.middleware.AuthenticationMiddleware',
 'django.contrib.messages.middleware.MessageMiddleware',
 'django.middleware.clickjacking.XFrameOptionsMiddleware',
 'django.middleware.security.SecurityMiddleware',
 'utilities.middleware.ExceptionHandlingMiddleware',
 'utilities.middleware.LoginRequiredMiddleware',
 'utilities.middleware.APIVersionMiddleware',
 'extras.middleware.ObjectChangeMiddleware',
 'django_prometheus.middleware.PrometheusAfterMiddleware')

Traceback:

File "/usr/lib/python3.8/site-packages/django/core/handlers/exception.py" in inner
  34.             response = get_response(request)

File "/usr/lib/python3.8/site-packages/django/core/handlers/base.py" in _get_response
  115.                 response = self.process_exception_by_middleware(e, request)

File "/usr/lib/python3.8/site-packages/django/core/handlers/base.py" in _get_response
  113.                 response = wrapped_callback(request, *callback_args, **callback_kwargs)

File "/usr/lib/python3.8/site-packages/django/views/decorators/csrf.py" in wrapped_view
  54.         return view_func(*args, **kwargs)

File "/usr/lib/python3.8/site-packages/rest_framework/viewsets.py" in view
  114.             return self.dispatch(request, *args, **kwargs)

File "/opt/netbox/netbox/utilities/api.py" in dispatch
  321.             return super().dispatch(request, *args, **kwargs)

File "/usr/lib/python3.8/site-packages/rest_framework/views.py" in dispatch
  505.             response = self.handle_exception(exc)

File "/usr/lib/python3.8/site-packages/rest_framework/views.py" in handle_exception
  465.             self.raise_uncaught_exception(exc)

File "/usr/lib/python3.8/site-packages/rest_framework/views.py" in raise_uncaught_exception
  476.         raise exc

File "/usr/lib/python3.8/site-packages/rest_framework/views.py" in dispatch
  502.             response = handler(request, *args, **kwargs)

File "/usr/lib/python3.8/site-packages/rest_framework/mixins.py" in create
  17.         serializer = self.get_serializer(data=request.data)

File "/opt/netbox/netbox/utilities/api.py" in get_serializer
  303.         return super().get_serializer(*args, **kwargs)

File "/usr/lib/python3.8/site-packages/rest_framework/generics.py" in get_serializer
  110.         return serializer_class(*args, **kwargs)

File "/opt/netbox/netbox/extras/api/customfields.py" in __init__
  132.                 self.initial_data['custom_fields'] = {}

File "/usr/lib/python3.8/site-packages/django/http/request.py" in __setitem__
  459.         self._assert_mutable()

File "/usr/lib/python3.8/site-packages/django/http/request.py" in _assert_mutable
  456.             raise AttributeError("This QueryDict instance is immutable")

Exception Type: AttributeError at /api/ipam/prefixes/
Exception Value: This QueryDict instance is immutable
Request information:
USER: admin

GET: No GET data

POST:
{   "prefix" : "10.147.8.0/22",   "status" : "container"} = ''

FILES: No FILES data

COOKIES: No cookie data

META:
CONTENT_LENGTH = '57'
CONTENT_TYPE = 'application/x-www-form-urlencoded'
HTTP_ACCEPT = 'application/json'
HTTP_AUTHORIZATION = 'Token ceda9bc3a5d14bf8df32f4eb6a94a96d7b38753a'
HTTP_HOST = 'exile.hepazulian.net:8001'
HTTP_USER_AGENT = 'curl/7.63.0'
PATH_INFO = '/api/ipam/prefixes/'
QUERY_STRING = ''
RAW_URI = '/api/ipam/prefixes/'
REMOTE_ADDR = '127.0.0.1'
REMOTE_PORT = '43564'
REQUEST_METHOD = 'POST'
SCRIPT_NAME = ''
SERVER_NAME = '127.0.0.1'
SERVER_PORT = '8001'
SERVER_PROTOCOL = 'HTTP/1.1'
SERVER_SOFTWARE = 'gunicorn/20.0.4'
gunicorn.socket = <socket.socket fd=11, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0, laddr=('127.0.0.1', 8001), raddr=('127.0.0.1', 43564)>
wsgi.errors = <gunicorn.http.wsgi.WSGIErrorsWrapper object at 0x7f2225ced0a0>
wsgi.file_wrapper = ''
wsgi.input = <gunicorn.http.body.Body object at 0x7f22261f2700>
wsgi.input_terminated = True
wsgi.multiprocess = True
wsgi.multithread = True
wsgi.run_once = False
wsgi.url_scheme = 'http'
wsgi.version = '(1, 0)'

Settings:
Using settings module netbox.settings
ABSOLUTE_URL_OVERRIDES = {}
ADMINS = []
ALLOWED_HOSTS = ['mojo.hepazulian.net', 'wormhole.hepazulian.net', 'exile.hepazulian.net']
APPEND_SLASH = True
AUTHENTICATION_BACKENDS = ['utilities.auth_backends.ViewExemptModelBackend']
AUTH_PASSWORD_VALIDATORS = '********************'
AUTH_USER_MODEL = 'auth.User'
BANNER_BOTTOM = ''
BANNER_LOGIN = ''
BANNER_TOP = ''
BASE_DIR = '/opt/netbox/netbox'
BASE_PATH = ''
CACHEOPS = {'auth.user': {'ops': 'get', 'timeout': 900}, 'auth.*': {'ops': ('fetch', 'get')}, 'auth.permission': {'ops': 'all'}, 'circuits.*': {'ops': 'all'}, 'dcim.*': {'ops': 'all'}, 'ipam.*': {'ops': 'all'}, 'extras.*': {'ops': 'all'}, 'secrets.*': '********************', 'users.*': {'ops': 'all'}, 'tenancy.*': {'ops': 'all'}, 'virtualization.*': {'ops': 'all'}}
CACHEOPS_DEFAULTS = {'timeout': 900}
CACHEOPS_DEGRADE_ON_FAILURE = True
CACHEOPS_ENABLED = True
CACHEOPS_REDIS = 'redis://localhost:6379/0'
CACHES = {'default': {'BACKEND': 'django.core.cache.backends.locmem.LocMemCache'}}
CACHE_MIDDLEWARE_ALIAS = 'default'
CACHE_MIDDLEWARE_KEY_PREFIX = '********************'
CACHE_MIDDLEWARE_SECONDS = 600
CACHE_TIMEOUT = 900
CACHING_REDIS = {'HOST': 'localhost', 'PORT': 6379, 'PASSWORD': '********************', 'DATABASE': 0, 'DEFAULT_TIMEOUT': 300, 'SSL': False}
CACHING_REDIS_DATABASE = 0
CACHING_REDIS_DEFAULT_TIMEOUT = 300
CACHING_REDIS_HOST = 'localhost'
CACHING_REDIS_PASSWORD = '********************'
CACHING_REDIS_PORT = 6379
CACHING_REDIS_SENTINELS = []
CACHING_REDIS_SENTINEL_SERVICE = 'default'
CACHING_REDIS_SSL = False
CACHING_REDIS_USING_SENTINEL = False
CHANGELOG_RETENTION = 90
CORS_ORIGIN_ALLOW_ALL = False
CORS_ORIGIN_REGEX_WHITELIST = []
CORS_ORIGIN_WHITELIST = []
CSRF_COOKIE_AGE = 31449600
CSRF_COOKIE_DOMAIN = None
CSRF_COOKIE_HTTPONLY = False
CSRF_COOKIE_NAME = 'csrftoken'
CSRF_COOKIE_PATH = '/'
CSRF_COOKIE_SAMESITE = 'Lax'
CSRF_COOKIE_SECURE = False
CSRF_FAILURE_VIEW = 'django.views.csrf.csrf_failure'
CSRF_HEADER_NAME = 'HTTP_X_CSRFTOKEN'
CSRF_TRUSTED_ORIGINS = ['mojo.hepazulian.net', 'wormhole.hepazulian.net', 'exile.hepazulian.net']
CSRF_USE_SESSIONS = False
DATABASE = {'NAME': 'netbox', 'USER': 'netbox', 'PASSWORD': '********************', 'HOST': 'localhost', 'PORT': '', 'ENGINE': 'django.db.backends.postgresql', 'ATOMIC_REQUESTS': False, 'AUTOCOMMIT': True, 'CONN_MAX_AGE': 0, 'OPTIONS': {}, 'TIME_ZONE': None, 'TEST': {'CHARSET': None, 'COLLATION': None, 'NAME': None, 'MIRROR': None}}
DATABASES = {'default': {'NAME': 'netbox', 'USER': 'netbox', 'PASSWORD': '********************', 'HOST': 'localhost', 'PORT': '', 'ENGINE': 'django.db.backends.postgresql', 'ATOMIC_REQUESTS': False, 'AUTOCOMMIT': True, 'CONN_MAX_AGE': 0, 'OPTIONS': {}, 'TIME_ZONE': None, 'TEST': {'CHARSET': None, 'COLLATION': None, 'NAME': None, 'MIRROR': None}}}
DATABASE_ROUTERS = []
DATA_UPLOAD_MAX_MEMORY_SIZE = 2621440
DATA_UPLOAD_MAX_NUMBER_FIELDS = None
DATETIME_FORMAT = 'N j, Y g:i a'
DATETIME_INPUT_FORMATS = ['%Y-%m-%d %H:%M:%S', '%Y-%m-%d %H:%M:%S.%f', '%Y-%m-%d %H:%M', '%Y-%m-%d', '%m/%d/%Y %H:%M:%S', '%m/%d/%Y %H:%M:%S.%f', '%m/%d/%Y %H:%M', '%m/%d/%Y', '%m/%d/%y %H:%M:%S', '%m/%d/%y %H:%M:%S.%f', '%m/%d/%y %H:%M', '%m/%d/%y']
DATE_FORMAT = 'N j, Y'
DATE_INPUT_FORMATS = ['%Y-%m-%d', '%m/%d/%Y', '%m/%d/%y', '%b %d %Y', '%b %d, %Y', '%d %b %Y', '%d %b, %Y', '%B %d %Y', '%B %d, %Y', '%d %B %Y', '%d %B, %Y']
DEBUG = True
DEBUG_PROPAGATE_EXCEPTIONS = False
DECIMAL_SEPARATOR = '.'
DEFAULT_CHARSET = 'utf-8'
DEFAULT_CONTENT_TYPE = 'text/html'
DEFAULT_EXCEPTION_REPORTER_FILTER = 'django.views.debug.SafeExceptionReporterFilter'
DEFAULT_FILE_STORAGE = 'django.core.files.storage.FileSystemStorage'
DEFAULT_FROM_EMAIL = 'webmaster@localhost'
DEFAULT_INDEX_TABLESPACE = ''
DEFAULT_TABLESPACE = ''
DEVELOPER = False
DISALLOWED_USER_AGENTS = []
EMAIL = {'SERVER': 'localhost', 'PORT': 25, 'USERNAME': '', 'PASSWORD': '********************', 'TIMEOUT': 10, 'FROM_EMAIL': ''}
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
EMAIL_HOST = 'localhost'
EMAIL_HOST_PASSWORD = '********************'
EMAIL_HOST_USER = ''
EMAIL_PORT = 25
EMAIL_SSL_CERTFILE = None
EMAIL_SSL_KEYFILE = '********************'
EMAIL_SUBJECT_PREFIX = '[NetBox] '
EMAIL_TIMEOUT = 10
EMAIL_USE_LOCALTIME = False
EMAIL_USE_SSL = False
EMAIL_USE_TLS = False
ENFORCE_GLOBAL_UNIQUE = False
EXEMPT_VIEW_PERMISSIONS = []
FILE_CHARSET = 'utf-8'
FILE_UPLOAD_DIRECTORY_PERMISSIONS = None
FILE_UPLOAD_HANDLERS = ['django.core.files.uploadhandler.MemoryFileUploadHandler', 'django.core.files.uploadhandler.TemporaryFileUploadHandler']
FILE_UPLOAD_MAX_MEMORY_SIZE = 2621440
FILE_UPLOAD_PERMISSIONS = None
FILE_UPLOAD_TEMP_DIR = None
FILTERS_NULL_CHOICE_LABEL = 'None'
FILTERS_NULL_CHOICE_VALUE = 'null'
FIRST_DAY_OF_WEEK = 0
FIXTURE_DIRS = []
FORCE_SCRIPT_NAME = None
FORMAT_MODULE_PATH = None
FORM_RENDERER = 'django.forms.renderers.DjangoTemplates'
HOSTNAME = 'mojo.hepazulian.net'
IGNORABLE_404_URLS = []
INSTALLED_APPS = ['django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'django.contrib.humanize', 'cacheops', 'corsheaders', 'debug_toolbar', 'django_filters', 'django_rq', 'django_tables2', 'django_prometheus', 'mptt', 'rest_framework', 'taggit', 'taggit_serializer', 'timezone_field', 'circuits', 'dcim', 'ipam', 'extras', 'secrets', 'tenancy', 'users', 'utilities', 'virtualization', 'drf_yasg']
INTERNAL_IPS = "('127.0.0.1', '::1')"
LANGUAGES = [('af', 'Afrikaans'), ('ar', 'Arabic'), ('ast', 'Asturian'), ('az', 'Azerbaijani'), ('bg', 'Bulgarian'), ('be', 'Belarusian'), ('bn', 'Bengali'), ('br', 'Breton'), ('bs', 'Bosnian'), ('ca', 'Catalan'), ('cs', 'Czech'), ('cy', 'Welsh'), ('da', 'Danish'), ('de', 'German'), ('dsb', 'Lower Sorbian'), ('el', 'Greek'), ('en', 'English'), ('en-au', 'Australian English'), ('en-gb', 'British English'), ('eo', 'Esperanto'), ('es', 'Spanish'), ('es-ar', 'Argentinian Spanish'), ('es-co', 'Colombian Spanish'), ('es-mx', 'Mexican Spanish'), ('es-ni', 'Nicaraguan Spanish'), ('es-ve', 'Venezuelan Spanish'), ('et', 'Estonian'), ('eu', 'Basque'), ('fa', 'Persian'), ('fi', 'Finnish'), ('fr', 'French'), ('fy', 'Frisian'), ('ga', 'Irish'), ('gd', 'Scottish Gaelic'), ('gl', 'Galician'), ('he', 'Hebrew'), ('hi', 'Hindi'), ('hr', 'Croatian'), ('hsb', 'Upper Sorbian'), ('hu', 'Hungarian'), ('hy', 'Armenian'), ('ia', 'Interlingua'), ('id', 'Indonesian'), ('io', 'Ido'), ('is', 'Icelandic'), ('it', 'Italian'), ('ja', 'Japanese'), ('ka', 'Georgian'), ('kab', 'Kabyle'), ('kk', 'Kazakh'), ('km', 'Khmer'), ('kn', 'Kannada'), ('ko', 'Korean'), ('lb', 'Luxembourgish'), ('lt', 'Lithuanian'), ('lv', 'Latvian'), ('mk', 'Macedonian'), ('ml', 'Malayalam'), ('mn', 'Mongolian'), ('mr', 'Marathi'), ('my', 'Burmese'), ('nb', 'Norwegian Bokmål'), ('ne', 'Nepali'), ('nl', 'Dutch'), ('nn', 'Norwegian Nynorsk'), ('os', 'Ossetic'), ('pa', 'Punjabi'), ('pl', 'Polish'), ('pt', 'Portuguese'), ('pt-br', 'Brazilian Portuguese'), ('ro', 'Romanian'), ('ru', 'Russian'), ('sk', 'Slovak'), ('sl', 'Slovenian'), ('sq', 'Albanian'), ('sr', 'Serbian'), ('sr-latn', 'Serbian Latin'), ('sv', 'Swedish'), ('sw', 'Swahili'), ('ta', 'Tamil'), ('te', 'Telugu'), ('th', 'Thai'), ('tr', 'Turkish'), ('tt', 'Tatar'), ('udm', 'Udmurt'), ('uk', 'Ukrainian'), ('ur', 'Urdu'), ('vi', 'Vietnamese'), ('zh-hans', 'Simplified Chinese'), ('zh-hant', 'Traditional Chinese')]
LANGUAGES_BIDI = ['he', 'ar', 'fa', 'ur']
LANGUAGE_CODE = 'en-us'
LANGUAGE_COOKIE_AGE = None
LANGUAGE_COOKIE_DOMAIN = None
LANGUAGE_COOKIE_NAME = 'django_language'
LANGUAGE_COOKIE_PATH = '/'
LDAP_CONFIG = None
LOCALE_PATHS = []
LOGGING = {'version': 1, 'disable_existing_loggers': False, 'handlers': {'file': {'level': 'DEBUG', 'class': 'logging.FileHandler', 'filename': '/var/log/netbox.log'}}, 'loggers': {'django': {'handlers': ['file'], 'level': 'DEBUG'}}}
LOGGING_CONFIG = 'logging.config.dictConfig'
LOGIN_REDIRECT_URL = '/accounts/profile/'
LOGIN_REQUIRED = True
LOGIN_TIMEOUT = None
LOGIN_URL = '/login/'
LOGOUT_REDIRECT_URL = None
MAINTENANCE_MODE = False
MANAGERS = []
MAX_PAGE_SIZE = 1000
MEDIA_ROOT = '/opt/netbox/netbox/media'
MEDIA_URL = '/media/'
MESSAGE_STORAGE = 'django.contrib.messages.storage.fallback.FallbackStorage'
MESSAGE_TAGS = {40: 'danger'}
METRICS_ENABLED = False
MIDDLEWARE = "('debug_toolbar.middleware.DebugToolbarMiddleware', 'django_prometheus.middleware.PrometheusBeforeMiddleware', 'corsheaders.middleware.CorsMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', 'django.middleware.common.CommonMiddleware', 'django.middleware.csrf.CsrfViewMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.messages.middleware.MessageMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware', 'django.middleware.security.SecurityMiddleware', 'utilities.middleware.ExceptionHandlingMiddleware', 'utilities.middleware.LoginRequiredMiddleware', 'utilities.middleware.APIVersionMiddleware', 'extras.middleware.ObjectChangeMiddleware', 'django_prometheus.middleware.PrometheusAfterMiddleware')"
MIGRATION_MODULES = {}
MONTH_DAY_FORMAT = 'F j'
NAPALM_ARGS = {}
NAPALM_PASSWORD = '********************'
NAPALM_TIMEOUT = 30
NAPALM_USERNAME = ''
NUMBER_GROUPING = 0
PAGINATE_COUNT = 50
PASSWORD_HASHERS = '********************'
PASSWORD_RESET_TIMEOUT_DAYS = '********************'
PER_PAGE_DEFAULTS = [25, 50, 100, 250, 500, 1000]
PREFER_IPV4 = False
PREPEND_WWW = False
PROMETHEUS_EXPORT_MIGRATIONS = False
REDIS = {'webhooks': {'HOST': 'localhost', 'PORT': 6379, 'PASSWORD': '********************', 'DATABASE': 0, 'DEFAULT_TIMEOUT': 300, 'SSL': False}, 'caching': {'HOST': 'localhost', 'PORT': 6379, 'PASSWORD': '********************', 'DATABASE': 0, 'DEFAULT_TIMEOUT': 300, 'SSL': False}}
REDIS_CACHE_CON_STRING = 'redis://localhost:6379/0'
REPORTS_ROOT = '/opt/netbox/netbox/reports'
REST_FRAMEWORK = {'ALLOWED_VERSIONS': ['2.7'], 'DEFAULT_AUTHENTICATION_CLASSES': ('rest_framework.authentication.SessionAuthentication', 'netbox.api.TokenAuthentication'), 'DEFAULT_FILTER_BACKENDS': ('django_filters.rest_framework.DjangoFilterBackend',), 'DEFAULT_PAGINATION_CLASS': 'netbox.api.OptionalLimitOffsetPagination', 'DEFAULT_PERMISSION_CLASSES': ('netbox.api.TokenPermissions',), 'DEFAULT_RENDERER_CLASSES': ('rest_framework.renderers.JSONRenderer', 'netbox.api.FormlessBrowsableAPIRenderer'), 'DEFAULT_VERSION': '2.7', 'DEFAULT_VERSIONING_CLASS': 'rest_framework.versioning.AcceptHeaderVersioning', 'PAGE_SIZE': 50, 'VIEW_NAME_FUNCTION': 'netbox.api.get_view_name'}
REST_FRAMEWORK_VERSION = '2.7'
ROOT_URLCONF = 'netbox.urls'
RQ_QUEUES = {'default': {'HOST': 'localhost', 'PORT': 6379, 'DB': 0, 'PASSWORD': '********************', 'DEFAULT_TIMEOUT': 300, 'SSL': False}}
SCRIPTS_ROOT = '/opt/netbox/netbox/scripts'
SECRETS_MIN_PUBKEY_SIZE = '********************'
SECRET_KEY = '********************'
SECURE_BROWSER_XSS_FILTER = False
SECURE_CONTENT_TYPE_NOSNIFF = False
SECURE_HSTS_INCLUDE_SUBDOMAINS = False
SECURE_HSTS_PRELOAD = False
SECURE_HSTS_SECONDS = 0
SECURE_PROXY_SSL_HEADER = "('HTTP_X_FORWARDED_PROTO', 'https')"
SECURE_REDIRECT_EXEMPT = []
SECURE_SSL_HOST = None
SECURE_SSL_REDIRECT = False
SERVER_EMAIL = ''
SESSION_CACHE_ALIAS = 'default'
SESSION_COOKIE_AGE = 1209600
SESSION_COOKIE_DOMAIN = None
SESSION_COOKIE_HTTPONLY = True
SESSION_COOKIE_NAME = 'sessionid'
SESSION_COOKIE_PATH = '/'
SESSION_COOKIE_SAMESITE = 'Lax'
SESSION_COOKIE_SECURE = False
SESSION_ENGINE = 'django.contrib.sessions.backends.db'
SESSION_EXPIRE_AT_BROWSER_CLOSE = False
SESSION_FILE_PATH = None
SESSION_SAVE_EVERY_REQUEST = False
SESSION_SERIALIZER = 'django.contrib.sessions.serializers.JSONSerializer'
SETTINGS_MODULE = 'netbox.settings'
SHORT_DATETIME_FORMAT = 'Y-m-d H:i'
SHORT_DATE_FORMAT = 'Y-m-d'
SHORT_TIME_FORMAT = 'H:i:s'
SIGNING_BACKEND = 'django.core.signing.TimestampSigner'
SILENCED_SYSTEM_CHECKS = []
STATICFILES_DIRS = "('/opt/netbox/netbox/project-static',)"
STATICFILES_FINDERS = ['django.contrib.staticfiles.finders.FileSystemFinder', 'django.contrib.staticfiles.finders.AppDirectoriesFinder']
STATICFILES_STORAGE = 'django.contrib.staticfiles.storage.StaticFilesStorage'
STATIC_ROOT = '/opt/netbox/netbox/static'
STATIC_URL = '/static/'
STORAGE_BACKEND = None
STORAGE_CONFIG = {}
SWAGGER_SETTINGS = {'DEFAULT_AUTO_SCHEMA_CLASS': 'utilities.custom_inspectors.NetBoxSwaggerAutoSchema', 'DEFAULT_FIELD_INSPECTORS': ['utilities.custom_inspectors.NullableBooleanFieldInspector', 'utilities.custom_inspectors.CustomChoiceFieldInspector', 'utilities.custom_inspectors.TagListFieldInspector', 'utilities.custom_inspectors.SerializedPKRelatedFieldInspector', 'drf_yasg.inspectors.CamelCaseJSONFilter', 'drf_yasg.inspectors.ReferencingSerializerInspector', 'drf_yasg.inspectors.RelatedFieldInspector', 'drf_yasg.inspectors.ChoiceFieldInspector', 'drf_yasg.inspectors.FileFieldInspector', 'drf_yasg.inspectors.DictFieldInspector', 'drf_yasg.inspectors.SerializerMethodFieldInspector', 'drf_yasg.inspectors.SimpleFieldInspector', 'drf_yasg.inspectors.StringDefaultFieldInspector'], 'DEFAULT_FILTER_INSPECTORS': ['utilities.custom_inspectors.IdInFilterInspector', 'drf_yasg.inspectors.CoreAPICompatInspector'], 'DEFAULT_INFO': 'netbox.urls.openapi_info', 'DEFAULT_MODEL_DEPTH': 1, 'DEFAULT_PAGINATOR_INSPECTORS': ['utilities.custom_inspectors.NullablePaginatorInspector', 'drf_yasg.inspectors.DjangoRestResponsePagination', 'drf_yasg.inspectors.CoreAPICompatInspector'], 'SECURITY_DEFINITIONS': {'Bearer': {'type': 'apiKey', 'name': 'Authorization', 'in': 'header'}}, 'VALIDATOR_URL': None}
TEMPLATES = [{'BACKEND': 'django.template.backends.django.DjangoTemplates', 'DIRS': ['/opt/netbox/netbox/templates'], 'APP_DIRS': True, 'OPTIONS': {'context_processors': ['django.template.context_processors.debug', 'django.template.context_processors.request', 'django.template.context_processors.media', 'django.contrib.auth.context_processors.auth', 'django.contrib.messages.context_processors.messages', 'utilities.context_processors.settings']}}]
TEMPLATES_DIR = '/opt/netbox/netbox/templates'
TEST_NON_SERIALIZED_APPS = []
TEST_RUNNER = 'django.test.runner.DiscoverRunner'
THOUSAND_SEPARATOR = ','
TIME_FORMAT = 'g:i a'
TIME_INPUT_FORMATS = ['%H:%M:%S', '%H:%M:%S.%f', '%H:%M']
TIME_ZONE = 'UTC'
USE_I18N = True
USE_L10N = False
USE_THOUSAND_SEPARATOR = False
USE_TZ = True
USE_X_FORWARDED_HOST = True
USE_X_FORWARDED_PORT = False
VERSION = '2.7.8'
WEBHOOKS_REDIS = {'HOST': 'localhost', 'PORT': 6379, 'PASSWORD': '********************', 'DATABASE': 0, 'DEFAULT_TIMEOUT': 300, 'SSL': False}
WEBHOOKS_REDIS_DATABASE = 0
WEBHOOKS_REDIS_DEFAULT_TIMEOUT = 300
WEBHOOKS_REDIS_HOST = 'localhost'
WEBHOOKS_REDIS_PASSWORD = '********************'
WEBHOOKS_REDIS_PORT = 6379
WEBHOOKS_REDIS_SENTINELS = []
WEBHOOKS_REDIS_SENTINEL_SERVICE = 'default'
WEBHOOKS_REDIS_SSL = False
WEBHOOKS_REDIS_USING_SENTINEL = False
WSGI_APPLICATION = 'netbox.wsgi.application'
X_FRAME_OPTIONS = 'SAMEORIGIN'
YEAR_MONTH_FORMAT = 'F Y'
jeremystretch commented 4 years ago

Please revise your bug report so that it entails only a raw curl request and its response. Wrap CLI commands and output in triple backticks (```) so that they are legible.

DanSheps commented 4 years ago

In addition to @jeremystretch's comment, this is not reproducible on master:

[root@miyu ~]# curl -X POST "https://master.netbox.dansheps.com/api/ipam/prefixes/" -H "accept: application/json" -H "Content-Type: application/json" -H "Authorization: Token XXX" -d '{ "prefix": "10.4.0.0/16", "status": "container"}'

{"id":22,"family":{"value":4,"label":"IPv4"},"prefix":"10.4.0.0/16","site":null,"vrf":null,"tenant":null,"vlan":null,"status":{"value":"container","label":"Container","id":0},"role":null,"is_pool":false,"description":"","tags":[],"created":"2020-02-27","last_updated":"2020-02-27T13:55:53.379230Z"}
[root@miyu ~]#
ross-alexander commented 4 years ago

Apologies and many thanks. The issue was I was missing the Content-type: application/json header. Once I had added that to the curl it worked on 2.7.8 with python 3.6.8 (Centos 8.1).

Many thanks for the quick response and again apologies for the my error.