Code development platform for open source projects from the European Union institutions :large_blue_circle: EU Login authentication by SMS has been phased out. To see alternatives please check here

Skip to content
Snippets Groups Projects
Commit 17e56bb1 authored by Frederico SEQUEIRA's avatar Frederico SEQUEIRA
Browse files

Merge branch 'check_compatibility_3_7_0' into 'main'

:arrow_up: Changes for plugin compatibility check with netbox 3.7.0

See merge request !88
parents 0fb4b32c 93dc3cc4
Branches
Tags v0.26.2
1 merge request!88⬆️ Changes for plugin compatibility check with netbox 3.7.0
Pipeline #307571 passed
Showing
with 142 additions and 91 deletions
......@@ -14,9 +14,16 @@ stages:
- test
- doc
- delivery
.parallel-hidden-job:
parallel:
matrix:
- NETBOX_VERSION: [v3.6.9, v3.7.0]
variables:
NETBOX_VERSION: v3.6.9
PROJECT_DIR: ".project-$NETBOX_VERSION"
init-job:
extends: .parallel-hidden-job
image: code.europa.eu:4567/digit-c4/dev/python-best-practices/python-poetry:3.11-alpine
stage: init
# We're trying to build python-poetry image based on python:3.11, but the Gitlab runner
......@@ -26,29 +33,32 @@ init-job:
before_script:
- apk add jpeg-dev zlib-dev libjpeg
script:
- mkdir .project
- git clone https://github.com/netbox-community/netbox.git -b $NETBOX_VERSION .project/netbox
- python -m venv .project/venv
- source .project/venv/bin/activate
- mkdir $PROJECT_DIR
- git clone https://github.com/netbox-community/netbox.git -b $NETBOX_VERSION $PROJECT_DIR/netbox
- python -m venv $PROJECT_DIR/venv
- export VENV="$PROJECT_DIR/venv"
- source $VENV/bin/activate
- pip install --upgrade pip
- poetry install
- pip install -r .project/netbox/requirements.txt -U
- pip install -r $PROJECT_DIR/netbox/requirements.txt -U
artifacts:
expire_in: 30 minutes
paths:
- .project/
- $PROJECT_DIR/
lint-job:
extends: .parallel-hidden-job
stage: lint
before_script:
- source .project/venv/bin/activate
- export VENV="$PROJECT_DIR/venv"
- source $VENV/bin/activate
- pip install pylint
script:
- pylint --rcfile .pylintrc --init-hook 'import os; import sys; sys.path.append(os.getcwd() + "/.project/netbox/netbox")' ./src/netbox_rps_plugin ./tests/
dependencies:
- init-job
- export PYTHONPATH="$PROJECT_DIR/netbox/netbox:$PYTHONPATH"
- pylint --rcfile .pylintrc ./src/netbox_rps_plugin ./tests/
needs:
- init-job
test-job:
extends: .parallel-hidden-job
image: code.europa.eu:4567/digit-c4/dev/python-best-practices/python-poetry:3.11-alpine
stage: test
services:
......@@ -60,87 +70,92 @@ test-job:
POSTGRES_PASSWORD: netbox
POSTGRES_HOST_AUTH_METHOD: trust
before_script:
- source .project/venv/bin/activate
- export VENV="$PROJECT_DIR/venv"
- source $VENV/bin/activate
- apk add jpeg-dev zlib-dev libjpeg
- ln -s $(pwd)/netbox_configuration/configuration_testing.py .project/netbox/netbox/netbox/configuration.py
- ln -s $(pwd)/netbox_configuration/configuration_testing.py $PROJECT_DIR/netbox/netbox/netbox/configuration.py
- pip install coverage
script:
- coverage run --include='*/src/netbox_rps_plugin/*' .project/netbox/netbox/manage.py test tests -v 2
- ls -al
- coverage run --include='*/src/netbox_rps_plugin/*' $PROJECT_DIR/netbox/netbox/manage.py test tests -v 2
- coverage report -m
- coverage xml -o .project/coverage.xml
- coverage xml -o $PROJECT_DIR/coverage.xml
artifacts:
expire_in: 1 day
reports:
coverage_report:
coverage_format: cobertura
path: .project/coverage.xml
dependencies:
- init-job
path: $PROJECT_DIR/coverage.xml
needs:
- init-job
doc-job:
stage: doc
services:
- postgres
- redis
only:
- main
variables:
NETBOX_VERSION: "v3.7.0"
PROJECT_DIR: ".project-v3.7.0"
POSTGRES_DB: netbox
POSTGRES_USER: netbox
POSTGRES_PASSWORD: netbox
POSTGRES_HOST_AUTH_METHOD: trust
services:
- postgres
- redis
before_script:
- apt-get update
- apt-get install -y graphviz graphviz-dev
- source .project/venv/bin/activate
- export VENV="$PROJECT_DIR/venv"
- source $VENV/bin/activate
- python3 -m pip install --upgrade Pillow
- ln -s $(pwd)/netbox_configuration/configuration_testing.py .project/netbox/netbox/netbox/configuration.py
- ln -s $(pwd)/docs .project/docs
- ln -s $(pwd)/netbox_configuration/configuration_testing.py $PROJECT_DIR/netbox/netbox/netbox/configuration.py
- ln -s $(pwd)/docs $PROJECT_DIR/docs
script:
- python3 .project/netbox/netbox/manage.py graph_models --pydot netbox_rps_plugin -o .project/docs/model/schema_diagram.png
- python3 $PROJECT_DIR/netbox/netbox/manage.py graph_models --pydot netbox_rps_plugin -o $PROJECT_DIR/docs/model/schema_diagram.png
artifacts:
expire_in: never
paths:
- .project/docs/*
dependencies:
- init-job
- $PROJECT_DIR/docs/*
needs:
- init-job
- job: init-job
parallel:
matrix:
- NETBOX_VERSION: [v3.7.0]
smithy-job:
stage: doc
variables:
NETBOX_VERSION: "v3.7.0"
PROJECT_DIR: ".project-v3.7.0"
before_script:
- mkdir -p smithy-install/smithy
- curl -L https://github.com/smithy-lang/smithy/releases/download/1.43.0/smithy-cli-linux-x86_64.tar.gz -o smithy-install/smithy-cli-linux-x86_64.tar.gz
- tar xvzf smithy-install/smithy-cli-linux-x86_64.tar.gz -C smithy-install/smithy
- smithy-install/smithy/install
- ln -s $(pwd)/docs .project/docs
- cd .project/docs/definition
- ln -s $(pwd)/docs $PROJECT_DIR/docs
- cd $PROJECT_DIR/docs/definition
script:
- smithy build
- cp build/smithy/openapi-conversion/openapi/rps.openapi.json ../rps.openapi.json
artifacts:
paths:
- .project/docs/rps.openapi.json
dependencies:
- init-job
- $PROJECT_DIR/docs/rps.openapi.json
needs:
- init-job
- job: init-job
parallel:
matrix:
- NETBOX_VERSION: [v3.7.0]
pages:
stage: doc
variables:
NETBOX_VERSION: "v3.7.0"
PROJECT_DIR: ".project-v3.7.0"
only:
- main
script:
- mkdir public
- cp docs/index.html public/index.html
- cp .project/docs/rps.openapi.json public/rps.openapi.json
- cp .project-v3.7.0/docs/rps.openapi.json public/rps.openapi.json
artifacts:
paths:
- public
dependencies:
- smithy-job
needs:
- smithy-job
......@@ -152,8 +167,14 @@ build-and-publish-package:
variables:
DRY_RUN: "no"
needs:
- lint-job
- test-job
- job: lint-job
parallel:
matrix:
- NETBOX_VERSION: [v3.6.9, v3.7.0]
- job: test-job
parallel:
matrix:
- NETBOX_VERSION: [v3.6.9, v3.7.0]
rules:
- when: manual
if: '$CI_COMMIT_TAG != null'
......@@ -4,6 +4,22 @@ A Netbox plugin for RPS mapping management.
![Screenshot of the Netbox RPS plugin detail screen](./docs/screenshot.png)
## Requirements
* NetBox 3.6.9 to 3.7.8
* Python 3.11 or higher
## Compatibility with NetBox Versions
NetBox Version | NetBox PLUGIN Version | Comment
-------------- | ------------------ | -------
3.6 | 0.26.2 |
3.7.* | 0.26.* |
4.0 | |
4.1 | |
4.2 | |
4.3 | |
## Contribute
### Option 1, Quick install (Debian tested).
......
......@@ -4,7 +4,7 @@ build-backend = "poetry.core.masonry.api"
[tool.poetry]
name = "netbox-rps-plugin"
version = "0.26.1"
version = "0.26.2"
# Family name last year contributors
authors = [
"David Jose DELASSUS",
......
# Generated by Django 4.2.13 on 2025-05-05 10:56
from django.db import migrations, models
import django.utils.timezone
class Migration(migrations.Migration):
dependencies = [
('netbox_rps_plugin', '0028_alter_redirect_options_and_more'),
]
operations = [
migrations.AlterField(
model_name='redirect',
name='activation_date',
field=models.DateTimeField(default=django.utils.timezone.now),
),
]
"""Models definitions"""
from typing import Any
from datetime import datetime
from datetime import datetime, timedelta
from urllib.parse import urlparse
from django.utils import timezone
from django.core.exceptions import ValidationError # pylint: disable=import-error
from django.conf import settings
from django.db import models # pylint: disable=import-error
......@@ -351,7 +352,7 @@ class Redirect(NetBoxModel):
default=RedirectTypeChoices.DEFAULT_VALUE,
) # Array of string, limited values
activation_date = models.DateTimeField(default=datetime.now) # Datetime, default is now
activation_date = models.DateTimeField(default=timezone.now) # Datetime, default is now
deactivation_date = models.DateTimeField(null=True, blank=True) # Datetime, can be null
class Meta:
......@@ -396,7 +397,7 @@ class Redirect(NetBoxModel):
Q(pattern=self.pattern) & (
(
Q(activation_date__gte=self.activation_date) &
Q(activation_date__lte=self.deactivation_date if self.deactivation_date else datetime.max)
Q(activation_date__lte=self.deactivation_date if self.deactivation_date else timezone.make_aware(datetime.max - timedelta(days=1)) )
) | (
Q(activation_date__lte=self.activation_date) &
(Q(deactivation_date__gte=self.activation_date) | Q(deactivation_date__isnull=True))
......
"""INIT FOR TESTS"""
import logging
logging.getLogger("django.request").setLevel(logging.ERROR)
File moved
File moved
......@@ -5,7 +5,7 @@ from django.contrib.contenttypes.models import ContentType # pylint: disable=im
from users.models import ObjectPermission # pylint: disable=import-error
from rest_framework import status # pylint: disable=import-error
from netbox_rps_plugin.models import Mapping, HstsProtocol
from netbox_rps_plugin.tests.base import BaseAPITestCase
from tests.base import BaseAPITestCase
class HstsProtocolApiTestCase(
......@@ -24,7 +24,6 @@ class HstsProtocolApiTestCase(
@classmethod
def setUpTestData(cls) -> None: # pylint: disable=invalid-name
"""Setup data to perform tests"""
logout_url = "https://logout.com"
mapp00= Mapping.objects.create(
source="https://truc10.com/api", target="http://10.10.10.10:1800/api",)
mapp01= Mapping.objects.create(
......@@ -39,13 +38,13 @@ class HstsProtocolApiTestCase(
source="https://truc15.com/api", target="http://10.10.10.15:1800/api",)
HstsProtocol.objects.create(
max_age=0, subdomains=True, preload_flag=True, logout_url=logout_url, mapping=mapp00
max_age=0, subdomains=True, preload_flag=True, mapping=mapp00
)
HstsProtocol.objects.create(
max_age=63072000, subdomains=True, preload_flag=True, logout_url=logout_url, mapping=mapp01
max_age=63072000, subdomains=True, preload_flag=True, mapping=mapp01
)
HstsProtocol.objects.create(
max_age=63072000, subdomains=True, preload_flag=False, logout_url=logout_url, mapping=mapp02
max_age=63072000, subdomains=True, preload_flag=False, mapping=mapp02
)
cls.create_data = [
......@@ -54,21 +53,18 @@ class HstsProtocolApiTestCase(
"subdomains": False,
"preload_flag": True,
"mapping": mapp03.pk,
"logout_url": logout_url,
},
{
"max_age": 63072000,
"subdomains": True,
"preload_flag": False,
"mapping": mapp04.pk,
"logout_url": logout_url,
},
{
"max_age": 31536000,
"subdomains": True,
"preload_flag": True,
"mapping": mapp05.pk,
"logout_url": logout_url,
},
]
......@@ -95,7 +91,6 @@ class HstsProtocolApiTestCase(
"subdomains": True,
"preload_flag": True,
"mapping": mapp06.pk,
"logout_url": "https://logout.com"
},
format="json",
**self.header,
......@@ -109,7 +104,6 @@ class HstsProtocolApiTestCase(
"subdomains": True,
"preload_flag": True,
"mapping": mapp06.pk,
"logout_url": "https://logout.com"
},
format="json",
**self.header,
......
"""HSTS Views Test Case"""
from utilities.testing import ViewTestCases # pylint: disable=import-error
from netbox_rps_plugin.tests.base import BaseModelViewTestCase
from tests.base import BaseModelViewTestCase
from netbox_rps_plugin.models import Mapping, HstsProtocol
class HstsProtocolTestCase(
......@@ -17,7 +17,6 @@ class HstsProtocolTestCase(
def setUpTestData(cls): # pylint: disable=invalid-name
"""Initial Data setup to perform the 'parent' ViewTestCases"""
default_max_age = 31536000
logout_url = "https://logout.com"
mapping1 = Mapping.objects.create(
source="https://truc00.com/api", target="http://10.10.10.11:1800/api"
)
......@@ -33,7 +32,6 @@ class HstsProtocolTestCase(
subdomains=False,
preload_flag=False,
max_age=default_max_age,
logout_url=logout_url,
)
hsts2 = HstsProtocol.objects.create(
......@@ -41,7 +39,6 @@ class HstsProtocolTestCase(
subdomains=True,
preload_flag=False,
max_age=default_max_age,
logout_url=logout_url,
)
cls.form_data = {
......@@ -49,7 +46,6 @@ class HstsProtocolTestCase(
"subdomains": True,
"preload_flag": False,
"max_age": default_max_age,
"logout_url": logout_url,
}
cls.csv_update_data = (
......
"""Host API Test Case"""
import json
from datetime import datetime, timedelta
import pytz
from datetime import timedelta
from django.utils import timezone
from django.contrib.contenttypes.models import ContentType # pylint: disable=import-error
from users.models import ObjectPermission # pylint: disable=import-error
from rest_framework import status # pylint: disable=import-error
......@@ -110,8 +110,8 @@ class RedirectApiTestCase(
"pattern": "/source/testmapping003/url(.*)",
"target": "https://target.testmapping003.url",
"redirect_type": RedirectTypeChoices.DEFAULT_VALUE,
"activation_date": datetime.now(pytz.timezone('Europe/Luxembourg')),
"deactivation_date": datetime.now(pytz.timezone('Europe/Luxembourg')) - timedelta(days=7)
"activation_date": timezone.now(),
"deactivation_date": timezone.now() - timedelta(days=7)
},
format="json",
**self.header,
......@@ -127,8 +127,8 @@ class RedirectApiTestCase(
"pattern": "/source/testmapping003/url(.*)",
"target": "https://target.testmapping003.url",
"redirect_type": RedirectTypeChoices.DEFAULT_VALUE,
"activation_date": datetime.now(pytz.timezone('Europe/Luxembourg')),
"deactivation_date": datetime.now(pytz.timezone('Europe/Luxembourg')) + timedelta(days=7)
"activation_date": timezone.now(),
"deactivation_date": timezone.now() + timedelta(days=7)
},
format="json",
**self.header,
......@@ -146,8 +146,8 @@ class RedirectApiTestCase(
"pattern": "/updatedsource/testmapping001/url(.*)",
"target": "https://updatedtarget.testmapping001.url",
"redirect_type": RedirectTypeChoices.DEFAULT_VALUE,
"activation_date": datetime.now(pytz.timezone('Europe/Luxembourg')),
"deactivation_date": datetime.now(pytz.timezone('Europe/Luxembourg')) + timedelta(days=-7)
"activation_date": timezone.now(),
"deactivation_date": timezone.now() + timedelta(days=-7)
},
format="json",
**self.header,
......@@ -182,7 +182,7 @@ class RedirectApiTestCase(
"pattern": "/source/testmapping004/url/^$*+?[]|(){}\\d\\w\\s",
"target": "https://target.testmapping004.url/^$*+?[]|(){}\\d\\w\\s",
"redirect_type": RedirectTypeChoices.DEFAULT_VALUE,
"activation_date": datetime.now(pytz.timezone('Europe/Luxembourg')),
"activation_date": timezone.now(),
},
format="json",
**self.header,
......@@ -200,7 +200,7 @@ class RedirectApiTestCase(
"pattern": "/source/testmapping004/url/^$*+?[]|(){}\\d\\w\\s",
"target": "https://updated.target.testmapping004.url/^$*+?[]|(){}\\d\\w\\s",
"redirect_type": RedirectTypeChoices.DEFAULT_VALUE,
"activation_date": datetime.now(pytz.timezone('Europe/Luxembourg')),
"activation_date": timezone.now(),
},
format="json",
**self.header,
......@@ -222,8 +222,8 @@ class RedirectApiTestCase(
pattern = "/source/testmapping005/url/redir010(.*)",
target = "http://target.testredirect010.url",
redirect_type = "1-1",
activation_date = datetime.now(pytz.timezone('Europe/Luxembourg')),
deactivation_date = datetime.now(pytz.timezone('Europe/Luxembourg')) + timedelta(days=7)
activation_date = timezone.now(),
deactivation_date = timezone.now() + timedelta(days=7)
)
# Add object-level permission
......@@ -245,8 +245,8 @@ class RedirectApiTestCase(
"pattern": "/source/testmapping005/url/redir010(.*)",
"target": "https://target.testmapping010.url",
"redirect_type": RedirectTypeChoices.DEFAULT_VALUE,
"activation_date": datetime.now(pytz.timezone('Europe/Luxembourg')),
"deactivation_date": datetime.now(pytz.timezone('Europe/Luxembourg')) + timedelta(days=7)
"activation_date": timezone.now(),
"deactivation_date": timezone.now() + timedelta(days=7)
},
format="json",
**self.header,
......@@ -263,7 +263,7 @@ class RedirectApiTestCase(
"pattern": "/source/testmapping005/url/redir010(.*)",
"target": "https://target.testmapping010.url",
"redirect_type": RedirectTypeChoices.DEFAULT_VALUE,
"activation_date": datetime.now(pytz.timezone('Europe/Luxembourg')) - timedelta(days=7)
"activation_date": timezone.now() - timedelta(days=7)
},
format="json",
**self.header,
......@@ -280,8 +280,8 @@ class RedirectApiTestCase(
"pattern": "/source/testmapping005/url/redir010(.*)",
"target": "https://target.testmapping010.url/redir010",
"redirect_type": RedirectTypeChoices.DEFAULT_VALUE,
"activation_date": datetime.now(pytz.timezone('Europe/Luxembourg')) - timedelta(days=7),
"deactivation_date": datetime.now(pytz.timezone('Europe/Luxembourg')) - timedelta(days=1)
"activation_date": timezone.now() - timedelta(days=7),
"deactivation_date": timezone.now() - timedelta(days=1)
},
format="json",
**self.header,
......@@ -299,8 +299,8 @@ class RedirectApiTestCase(
"pattern": "/source/testmapping005/url/redir010(.*)",
"target": "https://target.testmapping010.url/redir010",
"redirect_type": RedirectTypeChoices.DEFAULT_VALUE,
"activation_date": datetime.now(pytz.timezone('Europe/Luxembourg')),
"deactivation_date": datetime.now(pytz.timezone('Europe/Luxembourg')) + timedelta(days=14)
"activation_date": timezone.now(),
"deactivation_date": timezone.now() + timedelta(days=14)
},
format="json",
**self.header,
......
"""Redirect VIEW Test Case"""
from datetime import datetime, timedelta
import pytz
from datetime import timedelta
from django.utils import timezone
from django.contrib.contenttypes.models import ContentType # pylint: disable=import-error
from django.test import override_settings # pylint: disable=import-error
from users.models import ObjectPermission # pylint: disable=import-error
......@@ -9,6 +9,7 @@ from utilities.testing.utils import post_data # pylint: disable=import-error
from netbox_rps_plugin.models import Mapping, Redirect # pylint: disable=import-error
from tests.base import BaseModelViewTestCase
class RedirectViewTestCase(
BaseModelViewTestCase,
ViewTestCases.GetObjectViewTestCase,
......@@ -58,7 +59,7 @@ class RedirectViewTestCase(
"mapping": cls.mapp03.pk,
"pattern": "/source/testmapping003/url/redir06(.*)",
"target": "http://target.testredirect006.url",
"activation_date": datetime.now(pytz.timezone('Europe/Luxembourg')),
"activation_date": timezone.now(),
"redirect_type": "1-1",
}
cls.csv_data = (
......@@ -101,8 +102,8 @@ class RedirectViewTestCase(
"mapping": self.mapp03.pk,
"pattern": "/source/testmapping003/url/redir06(.*)",
"target": "http://target.testredirect066.url",
"activation_date": datetime.now(pytz.timezone('Europe/Luxembourg')),
"deactivation_date": datetime.now(pytz.timezone('Europe/Luxembourg')) - timedelta(days=7),
"activation_date": timezone.now(),
"deactivation_date": timezone.now() - timedelta(days=7),
"redirect_type": "1-1",
}),
}
......@@ -132,8 +133,8 @@ class RedirectViewTestCase(
"mapping": self.mapp03.pk,
"pattern": "/source/testmapping003/url/redir66(a{2})",
"target": "http://target.testredirect066.url",
"activation_date": datetime.now(pytz.timezone('Europe/Luxembourg')),
"deactivation_date": datetime.now(pytz.timezone('Europe/Luxembourg')) + timedelta(days=7),
"activation_date": timezone.now(),
"deactivation_date": timezone.now() + timedelta(days=7),
"redirect_type": "1-1",
}),
}
......@@ -147,8 +148,8 @@ class RedirectViewTestCase(
"mapping": self.mapp03.pk,
"pattern": "/source/testmapping003/url/redir66(a{2})",
"target": "http://target.testredirect076.url",
"activation_date": datetime.now(pytz.timezone('Europe/Luxembourg')) - timedelta(days=7),
"deactivation_date": datetime.now(pytz.timezone('Europe/Luxembourg')) + timedelta(days=14),
"activation_date": timezone.now() - timedelta(days=7),
"deactivation_date": timezone.now() + timedelta(days=14),
"redirect_type": "1-1",
}),
}
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment