From 6ee161bdc63cb726a7e603ef17c6e3246b7dfc4f Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Thu, 3 Dec 2020 12:11:44 -0500 Subject: [PATCH 1/9] Add references to GitHub discussions --- CONTRIBUTING.md | 28 +++++++++++++++++++++++----- README.md | 4 ++-- 2 files changed, 25 insertions(+), 7 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 136d9f493..85bb561dd 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -4,15 +4,33 @@ If you encounter any issues installing or using NetBox, try one of the following resources to get assistance. Please **do not** open a GitHub issue except to report bugs or request features. +### GitHub Discussions + +GitHub's discussions are the best place to get help or propose rough ideas for +new functionality. Their integration with GitHub allows for easily cross- +referencing and converting posts to issues as needed. There are several +categories for discussions: + +* **General** - General community discussion +* **Ideas** - Ideas for new functionality that isn't yet ready for a formal + feature request +* **Q&A** - Request help with installing or using NetBox +* **Show and tell** - Share a plugin, script, or something else you've made + using NetBox + ### Mailing List -We have established a Google Groups Mailing List for issues and general -discussion. This is the best forum for obtaining assistance with NetBox -installation. You can find us [here](https://groups.google.com/g/netbox-discuss). +We also have a Google Groups [mailing list](https://groups.google.com/g/netbox-discuss) +for general discussion, however we're encouraging people to use GitHub +discussions where possible, as it's much easier for newcomers to review past +discussions. ### Slack -For real-time discussion, you can join the #netbox Slack channel on [NetworkToCode](https://slack.networktocode.com/). +For real-time chat, you can join the **#netbox** Slack channel on [NetworkToCode](https://slack.networktocode.com/). +Unfortunately, the Slack channel does not provide long-term retention of chat +history, so try to avoid it for any discussions would benefit from being +preserved for future reference. ## Reporting Bugs @@ -171,7 +189,7 @@ overlooked. * Official channels for communication include: - * GitHub issues/pull requests + * GitHub issues, pull requests, and discussions * The [netbox-discuss](https://groups.google.com/g/netbox-discuss) mailing list * The **#netbox** channel on [NetworkToCode Slack](https://networktocode.slack.com/) diff --git a/README.md b/README.md index 284c5a87c..56c71af78 100644 --- a/README.md +++ b/README.md @@ -12,8 +12,8 @@ complete list of requirements, see `requirements.txt`. The code is available [on The complete documentation for NetBox can be found at [Read the Docs](http://netbox.readthedocs.io/en/stable/). -Questions? Comments? Please subscribe to [the netbox-discuss mailing list](https://groups.google.com/g/netbox-discuss), -or join us in the #netbox Slack channel on [NetworkToCode](https://networktocode.slack.com/)! +Questions? Comments? Please start a [discussion on GitHub](https://github.com/netbox-community/netbox/discussions), +or join us in the **#netbox** Slack channel on [NetworkToCode](https://networktocode.slack.com/)! ### Build Status From a4b2e1f2e2b618c0cdcfd6e62c50ecc6eaaa55d9 Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Thu, 3 Dec 2020 12:13:08 -0500 Subject: [PATCH 2/9] Fix typo (from PR #5393) --- docs/installation/5-http-server.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/installation/5-http-server.md b/docs/installation/5-http-server.md index 5b4e3dfae..5bd04253a 100644 --- a/docs/installation/5-http-server.md +++ b/docs/installation/5-http-server.md @@ -3,7 +3,7 @@ This documentation provides example configurations for both [nginx](https://www.nginx.com/resources/wiki/) and [Apache](http://httpd.apache.org/docs/2.4), though any HTTP server which supports WSGI should be compatible. !!! info - For the sake of brevity, only Ubuntu 18.04 instructions are provided here, these tasks not unique to NetBox and should carry over to other distributions with mininal changes. Please consult your distribution's documentation for assistance if needed. + For the sake of brevity, only Ubuntu 18.04 instructions are provided here, these tasks are not unique to NetBox and should carry over to other distributions with minimal changes. Please consult your distribution's documentation for assistance if needed. ## Obtain an SSL Certificate From 22bb700f94d13c818c87445e0c170c72b2e05a80 Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Thu, 3 Dec 2020 13:40:42 -0500 Subject: [PATCH 3/9] Fixes #5396: Fix uniqueness constraint for virtual machine names --- docs/release-notes/version-2.9.md | 1 + netbox/virtualization/models.py | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/release-notes/version-2.9.md b/docs/release-notes/version-2.9.md index 563220cb5..e755e7b82 100644 --- a/docs/release-notes/version-2.9.md +++ b/docs/release-notes/version-2.9.md @@ -5,6 +5,7 @@ ### Bug Fixes * [#5383](https://github.com/netbox-community/netbox/issues/5383) - Fix setting user password via REST API +* [#5396](https://github.com/netbox-community/netbox/issues/5396) - Fix uniqueness constraint for virtual machine names --- diff --git a/netbox/virtualization/models.py b/netbox/virtualization/models.py index 7a8bd7595..72d84a908 100644 --- a/netbox/virtualization/models.py +++ b/netbox/virtualization/models.py @@ -319,10 +319,10 @@ class VirtualMachine(ChangeLoggedModel, ConfigContextModel, CustomFieldModel): # because Django does not consider two NULL fields to be equal, and thus will not trigger a violation # of the uniqueness constraint without manual intervention. if self.tenant is None and VirtualMachine.objects.exclude(pk=self.pk).filter( - name=self.name, tenant__isnull=True + name=self.name, cluster=self.cluster, tenant__isnull=True ): raise ValidationError({ - 'name': 'A virtual machine with this name already exists.' + 'name': 'A virtual machine with this name already exists in the assigned cluster.' }) super().validate_unique(exclude) From d75696b30a489d57375e037712ec3fe1038f5cb7 Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Thu, 3 Dec 2020 14:15:48 -0500 Subject: [PATCH 4/9] Fixes #5407: Add direct link to secret on secrets list --- docs/release-notes/version-2.9.md | 1 + netbox/secrets/tables.py | 14 +++++++++++--- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/docs/release-notes/version-2.9.md b/docs/release-notes/version-2.9.md index e755e7b82..652f6d254 100644 --- a/docs/release-notes/version-2.9.md +++ b/docs/release-notes/version-2.9.md @@ -6,6 +6,7 @@ * [#5383](https://github.com/netbox-community/netbox/issues/5383) - Fix setting user password via REST API * [#5396](https://github.com/netbox-community/netbox/issues/5396) - Fix uniqueness constraint for virtual machine names +* [#5407](https://github.com/netbox-community/netbox/issues/5407) - Add direct link to secret on secrets list --- diff --git a/netbox/secrets/tables.py b/netbox/secrets/tables.py index 5e8c5a8b4..3302d0d19 100644 --- a/netbox/secrets/tables.py +++ b/netbox/secrets/tables.py @@ -28,12 +28,20 @@ class SecretRoleTable(BaseTable): class SecretTable(BaseTable): pk = ToggleColumn() - device = tables.LinkColumn() + id = tables.Column( + linkify=True + ) + device = tables.Column( + linkify=True + ) + role = tables.Column( + linkify=True + ) tags = TagColumn( url_name='secrets:secret_list' ) class Meta(BaseTable.Meta): model = Secret - fields = ('pk', 'device', 'role', 'name', 'last_updated', 'hash', 'tags') - default_columns = ('pk', 'device', 'role', 'name', 'last_updated') + fields = ('pk', 'id', 'device', 'role', 'name', 'last_updated', 'hash', 'tags') + default_columns = ('pk', 'id', 'device', 'role', 'name', 'last_updated') From 584b8109a0c8881d0195dccfc39f9571f380a80b Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Thu, 3 Dec 2020 15:22:44 -0500 Subject: [PATCH 5/9] Fixes #5408: Fix updating secrets without setting new plaintext --- docs/release-notes/version-2.9.md | 1 + netbox/secrets/views.py | 26 +++++++++++++------------- 2 files changed, 14 insertions(+), 13 deletions(-) diff --git a/docs/release-notes/version-2.9.md b/docs/release-notes/version-2.9.md index 652f6d254..7411ab149 100644 --- a/docs/release-notes/version-2.9.md +++ b/docs/release-notes/version-2.9.md @@ -7,6 +7,7 @@ * [#5383](https://github.com/netbox-community/netbox/issues/5383) - Fix setting user password via REST API * [#5396](https://github.com/netbox-community/netbox/issues/5396) - Fix uniqueness constraint for virtual machine names * [#5407](https://github.com/netbox-community/netbox/issues/5407) - Add direct link to secret on secrets list +* [#5408](https://github.com/netbox-community/netbox/issues/5408) - Fix updating secrets without setting new plaintext --- diff --git a/netbox/secrets/views.py b/netbox/secrets/views.py index e95392dfc..24138e0e4 100644 --- a/netbox/secrets/views.py +++ b/netbox/secrets/views.py @@ -108,13 +108,14 @@ class SecretEditView(ObjectEditView): if form.is_valid(): logger.debug("Form validation was successful") + secret = form.save(commit=False) - # We must have a session key in order to create a secret or update the plaintext of an existing secret - if (form.cleaned_data['plaintext'] or secret.pk is None) and session_key is None: + # We must have a session key in order to set the plaintext of a Secret + if form.cleaned_data['plaintext'] and session_key is None: logger.debug("Unable to proceed: No session key was provided with the request") form.add_error(None, "No session key was provided with the request. Unable to encrypt secret data.") - else: + elif form.cleaned_data['plaintext']: master_key = None try: sk = SessionKey.objects.get(userkey__user=request.user) @@ -125,19 +126,18 @@ class SecretEditView(ObjectEditView): if master_key is not None: logger.debug("Successfully resolved master key for encryption") - secret = form.save(commit=False) - if form.cleaned_data['plaintext']: - secret.plaintext = str(form.cleaned_data['plaintext']) + secret.plaintext = str(form.cleaned_data['plaintext']) secret.encrypt(master_key) - secret.save() - form.save_m2m() - msg = '{} secret'.format('Created' if not form.instance.pk else 'Modified') - logger.info(f"{msg} {secret} (PK: {secret.pk})") - msg = '{} {}'.format(msg, secret.get_absolute_url(), escape(secret)) - messages.success(request, mark_safe(msg)) + secret.save() + form.save_m2m() - return redirect(self.get_return_url(request, secret)) + msg = '{} secret'.format('Created' if not form.instance.pk else 'Modified') + logger.info(f"{msg} {secret} (PK: {secret.pk})") + msg = f'{msg} {escape(secret)}' + messages.success(request, mark_safe(msg)) + + return redirect(self.get_return_url(request, secret)) else: logger.debug("Form validation failed") From e7f64334c06748b4b85c54d881f5e2b03b9463b5 Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Fri, 4 Dec 2020 08:57:19 -0500 Subject: [PATCH 6/9] Fixes #5410: Restore tags field on cable connection forms --- docs/release-notes/version-2.9.md | 1 + netbox/dcim/forms.py | 18 +++++++++++++++--- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/docs/release-notes/version-2.9.md b/docs/release-notes/version-2.9.md index 7411ab149..a2b00dc12 100644 --- a/docs/release-notes/version-2.9.md +++ b/docs/release-notes/version-2.9.md @@ -8,6 +8,7 @@ * [#5396](https://github.com/netbox-community/netbox/issues/5396) - Fix uniqueness constraint for virtual machine names * [#5407](https://github.com/netbox-community/netbox/issues/5407) - Add direct link to secret on secrets list * [#5408](https://github.com/netbox-community/netbox/issues/5408) - Fix updating secrets without setting new plaintext +* [#5410](https://github.com/netbox-community/netbox/issues/5410) - Restore tags field on cable connection forms --- diff --git a/netbox/dcim/forms.py b/netbox/dcim/forms.py index 2132214a7..aa7537c7b 100644 --- a/netbox/dcim/forms.py +++ b/netbox/dcim/forms.py @@ -3502,12 +3502,16 @@ class ConnectCableToDeviceForm(BootstrapMixin, forms.ModelForm): 'rack_id': '$termination_b_rack', } ) + tags = DynamicModelMultipleChoiceField( + queryset=Tag.objects.all(), + required=False + ) class Meta: model = Cable fields = [ 'termination_b_region', 'termination_b_site', 'termination_b_rack', 'termination_b_device', - 'termination_b_id', 'type', 'status', 'label', 'color', 'length', 'length_unit', + 'termination_b_id', 'type', 'status', 'label', 'color', 'length', 'length_unit', 'tags', ] widgets = { 'status': StaticSelect2, @@ -3635,12 +3639,16 @@ class ConnectCableToCircuitTerminationForm(BootstrapMixin, forms.ModelForm): 'circuit_id': '$termination_b_circuit' } ) + tags = DynamicModelMultipleChoiceField( + queryset=Tag.objects.all(), + required=False + ) class Meta: model = Cable fields = [ 'termination_b_provider', 'termination_b_region', 'termination_b_site', 'termination_b_circuit', - 'termination_b_id', 'type', 'status', 'label', 'color', 'length', 'length_unit', + 'termination_b_id', 'type', 'status', 'label', 'color', 'length', 'length_unit', 'tags', ] def clean_termination_b_id(self): @@ -3688,12 +3696,16 @@ class ConnectCableToPowerFeedForm(BootstrapMixin, forms.ModelForm): 'power_panel_id': '$termination_b_powerpanel' } ) + tags = DynamicModelMultipleChoiceField( + queryset=Tag.objects.all(), + required=False + ) class Meta: model = Cable fields = [ 'termination_b_rackgroup', 'termination_b_powerpanel', 'termination_b_id', 'type', 'status', 'label', - 'color', 'length', 'length_unit', + 'color', 'length', 'length_unit', 'tags', ] def clean_termination_b_id(self): From cc5c000a6d027a7d60c9fe637113616413a94062 Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Tue, 8 Dec 2020 14:55:06 -0500 Subject: [PATCH 7/9] Move CI to GitHub Actions (#5431) Replaces Travis CI with GitHub Actions --- .github/workflows/ci.yml | 50 +++++++++++++++++++++ .travis.yml | 19 -------- README.md | 4 +- netbox/netbox/configuration.testing.py | 4 +- scripts/cibuild.sh | 60 -------------------------- 5 files changed, 54 insertions(+), 83 deletions(-) create mode 100644 .github/workflows/ci.yml delete mode 100644 .travis.yml delete mode 100755 scripts/cibuild.sh diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 000000000..232325774 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,50 @@ +name: CI +on: push +jobs: + build: + runs-on: ubuntu-latest + strategy: + matrix: + python-version: [3.6, 3.7] + services: + redis: + image: redis + ports: + - 6379:6379 + postgres: + image: postgres + env: + POSTGRES_USER: netbox + POSTGRES_PASSWORD: netbox + options: >- + --health-cmd pg_isready + --health-interval 10s + --health-timeout 5s + --health-retries 5 + ports: + - 5432:5432 + + steps: + - name: Check out repo + uses: actions/checkout@v2 + + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v2 + with: + python-version: ${{ matrix.python-version }} + + - name: Install dependencies & set up configuration + run: | + python -m pip install --upgrade pip + pip install -r requirements.txt + pip install pycodestyle coverage + ln -s configuration.testing.py netbox/netbox/configuration.py + + - name: Check PEP8 compliance + run: pycodestyle --ignore=W504,E501 netbox/ + + - name: Run tests + run: coverage run --source="netbox/" netbox/manage.py test netbox/ + + - name: Show coverage report + run: coverage report --skip-covered --omit *migrations* diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 0dcbd9ee1..000000000 --- a/.travis.yml +++ /dev/null @@ -1,19 +0,0 @@ -sudo: required -services: - - postgresql - - redis-server -addons: - postgresql: "9.6" -language: python -python: - - "3.6" - - "3.7" -install: - - pip install -r requirements.txt - - pip install pycodestyle - - pip install coverage -before_script: - - psql --version - - psql -U postgres -c 'SELECT version();' -script: - - ./scripts/cibuild.sh diff --git a/README.md b/README.md index 56c71af78..9d27844c2 100644 --- a/README.md +++ b/README.md @@ -19,8 +19,8 @@ or join us in the **#netbox** Slack channel on [NetworkToCode](https://networkto | | status | |-------------|------------| -| **master** | [![Build Status](https://travis-ci.org/netbox-community/netbox.svg?branch=master)](https://travis-ci.com/netbox-community/netbox/) | -| **develop** | [![Build Status](https://travis-ci.org/netbox-community/netbox.svg?branch=develop)](https://travis-ci.com/netbox-community/netbox/) | +| **master** | ![Build status](https://github.com/netbox-community/netbox/workflows/CI/badge.svg?branch=master) | +| **develop** | ![Build status](https://github.com/netbox-community/netbox/workflows/CI/badge.svg?branch=develop) | ### Screenshots diff --git a/netbox/netbox/configuration.testing.py b/netbox/netbox/configuration.testing.py index 066f94841..59529b80c 100644 --- a/netbox/netbox/configuration.testing.py +++ b/netbox/netbox/configuration.testing.py @@ -7,8 +7,8 @@ ALLOWED_HOSTS = ['*'] DATABASE = { 'NAME': 'netbox', - 'USER': '', - 'PASSWORD': '', + 'USER': 'netbox', + 'PASSWORD': 'netbox', 'HOST': 'localhost', 'PORT': '', 'CONN_MAX_AGE': 300, diff --git a/scripts/cibuild.sh b/scripts/cibuild.sh deleted file mode 100755 index 6a0422308..000000000 --- a/scripts/cibuild.sh +++ /dev/null @@ -1,60 +0,0 @@ -#!/bin/bash - -# Exit code starts at 0 but is modified if any checks fail -EXIT=0 - -# Output a line prefixed with a timestamp -info() -{ - echo "$(date +'%F %T') |" -} - -# Track number of seconds required to run script -START=$(date +%s) -echo "$(info) starting build checks." - -# Syntax check all python source files -SYNTAX=$(find . -name "*.py" -type f -exec python -m py_compile {} \; 2>&1) -if [[ ! -z $SYNTAX ]]; then - echo -e "$SYNTAX" - echo -e "\n$(info) detected one or more syntax errors, failing build." - EXIT=1 -fi - -# Check all python source files for PEP 8 compliance, but explicitly -# ignore: -# - W504: line break after binary operator -# - E501: line greater than 80 characters in length -pycodestyle \ - --ignore=W504,E501 \ - netbox/ -RC=$? -if [[ $RC != 0 ]]; then - echo -e "\n$(info) one or more PEP 8 errors detected, failing build." - EXIT=$RC -fi - -# Point to the testing configuration file for use in CI -ln -s configuration.testing.py netbox/netbox/configuration.py - -# Run NetBox tests -coverage run --source="netbox/" netbox/manage.py test netbox/ -RC=$? -if [[ $RC != 0 ]]; then - echo -e "\n$(info) one or more tests failed, failing build." - EXIT=$RC -fi - -# Show code coverage report -coverage report --skip-covered --omit *migrations* -RC=$? -if [[ $RC != 0 ]]; then - echo -e "\n$(info) failed to generate code coverage report." - EXIT=$RC -fi - -# Show build duration -END=$(date +%s) -echo "$(info) exiting with code $EXIT after $(($END - $START)) seconds." - -exit $EXIT From 27e27788cd307fea3f0030aafbe81f9472ab652f Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Tue, 8 Dec 2020 16:14:52 -0500 Subject: [PATCH 8/9] Closes #5424: Allow passing Python code to nbshell using --command --- docs/release-notes/version-2.9.md | 4 ++++ netbox/extras/management/commands/nbshell.py | 17 ++++++++++++++--- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/docs/release-notes/version-2.9.md b/docs/release-notes/version-2.9.md index a2b00dc12..b976c7fcd 100644 --- a/docs/release-notes/version-2.9.md +++ b/docs/release-notes/version-2.9.md @@ -2,6 +2,10 @@ ## v2.9.11 (FUTURE) +### Enhancements + +* [#5424](https://github.com/netbox-community/netbox/issues/5424) - Allow passing Python code to `nbshell` using `--command` + ### Bug Fixes * [#5383](https://github.com/netbox-community/netbox/issues/5383) - Fix setting user password via REST API diff --git a/netbox/extras/management/commands/nbshell.py b/netbox/extras/management/commands/nbshell.py index 48da46525..bcb5568b7 100644 --- a/netbox/extras/management/commands/nbshell.py +++ b/netbox/extras/management/commands/nbshell.py @@ -25,12 +25,18 @@ class Command(BaseCommand): help = "Start the Django shell with all NetBox models already imported" django_models = {} + def add_arguments(self, parser): + parser.add_argument( + '-c', '--command', + help='Python code to execute (instead of starting an interactive shell)', + ) + def _lsmodels(self): for app, models in self.django_models.items(): app_name = apps.get_app_config(app).verbose_name - print('{}:'.format(app_name)) + print(f'{app_name}:') for m in models: - print(' {}'.format(m)) + print(f' {m}') def get_namespace(self): namespace = {} @@ -46,7 +52,7 @@ class Command(BaseCommand): # Constants try: - app_constants = sys.modules['{}.constants'.format(app)] + app_constants = sys.modules[f'{app}.constants'] for name in dir(app_constants): namespace[name] = getattr(app_constants, name) except KeyError: @@ -64,5 +70,10 @@ class Command(BaseCommand): return namespace def handle(self, **options): + # If Python code has been passed, execute it and exit. + if options['command']: + exec(options['command'], self.get_namespace()) + return + shell = code.interact(banner=BANNER_TEXT, local=self.get_namespace()) return shell From e062cbb79f12dc26603c7aaa6288a7560097a7c1 Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Thu, 10 Dec 2020 08:52:55 -0500 Subject: [PATCH 9/9] Fixes #5436: Show assigned IP addresses in interfaces list --- docs/release-notes/version-2.9.md | 1 + netbox/dcim/tables.py | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/release-notes/version-2.9.md b/docs/release-notes/version-2.9.md index b976c7fcd..9187f9ff7 100644 --- a/docs/release-notes/version-2.9.md +++ b/docs/release-notes/version-2.9.md @@ -13,6 +13,7 @@ * [#5407](https://github.com/netbox-community/netbox/issues/5407) - Add direct link to secret on secrets list * [#5408](https://github.com/netbox-community/netbox/issues/5408) - Fix updating secrets without setting new plaintext * [#5410](https://github.com/netbox-community/netbox/issues/5410) - Restore tags field on cable connection forms +* [#5436](https://github.com/netbox-community/netbox/issues/5436) - Show assigned IP addresses in interfaces list --- diff --git a/netbox/dcim/tables.py b/netbox/dcim/tables.py index 2d8195f85..08235997d 100644 --- a/netbox/dcim/tables.py +++ b/netbox/dcim/tables.py @@ -141,7 +141,7 @@ POWERPANEL_POWERFEED_COUNT = """ """ INTERFACE_IPADDRESSES = """ -{% for ip in record.ip_addresses.unrestricted %} +{% for ip in record.ip_addresses.all %} {{ ip }}
{% endfor %} """