|
@@ -6,13 +6,9 @@ from contextlib import contextmanager
|
|
|
from pathlib import Path
|
|
from pathlib import Path
|
|
|
from urllib.parse import urlparse
|
|
from urllib.parse import urlparse
|
|
|
|
|
|
|
|
-import boto3
|
|
|
|
|
-from botocore.config import Config as Boto3Config
|
|
|
|
|
from django import forms
|
|
from django import forms
|
|
|
from django.conf import settings
|
|
from django.conf import settings
|
|
|
from django.utils.translation import gettext as _
|
|
from django.utils.translation import gettext as _
|
|
|
-from dulwich import porcelain
|
|
|
|
|
-from dulwich.config import ConfigDict
|
|
|
|
|
|
|
|
|
|
from netbox.registry import registry
|
|
from netbox.registry import registry
|
|
|
from .choices import DataSourceTypeChoices
|
|
from .choices import DataSourceTypeChoices
|
|
@@ -43,9 +39,20 @@ class DataBackend:
|
|
|
parameters = {}
|
|
parameters = {}
|
|
|
sensitive_parameters = []
|
|
sensitive_parameters = []
|
|
|
|
|
|
|
|
|
|
+ # Prevent Django's template engine from calling the backend
|
|
|
|
|
+ # class when referenced via DataSource.backend_class
|
|
|
|
|
+ do_not_call_in_templates = True
|
|
|
|
|
+
|
|
|
def __init__(self, url, **kwargs):
|
|
def __init__(self, url, **kwargs):
|
|
|
self.url = url
|
|
self.url = url
|
|
|
self.params = kwargs
|
|
self.params = kwargs
|
|
|
|
|
+ self.config = self.init_config()
|
|
|
|
|
+
|
|
|
|
|
+ def init_config(self):
|
|
|
|
|
+ """
|
|
|
|
|
+ Hook to initialize the instance's configuration.
|
|
|
|
|
+ """
|
|
|
|
|
+ return
|
|
|
|
|
|
|
|
@property
|
|
@property
|
|
|
def url_scheme(self):
|
|
def url_scheme(self):
|
|
@@ -58,6 +65,7 @@ class DataBackend:
|
|
|
|
|
|
|
|
@register_backend(DataSourceTypeChoices.LOCAL)
|
|
@register_backend(DataSourceTypeChoices.LOCAL)
|
|
|
class LocalBackend(DataBackend):
|
|
class LocalBackend(DataBackend):
|
|
|
|
|
+
|
|
|
@contextmanager
|
|
@contextmanager
|
|
|
def fetch(self):
|
|
def fetch(self):
|
|
|
logger.debug(f"Data source type is local; skipping fetch")
|
|
logger.debug(f"Data source type is local; skipping fetch")
|
|
@@ -89,14 +97,28 @@ class GitBackend(DataBackend):
|
|
|
}
|
|
}
|
|
|
sensitive_parameters = ['password']
|
|
sensitive_parameters = ['password']
|
|
|
|
|
|
|
|
|
|
+ def init_config(self):
|
|
|
|
|
+ from dulwich.config import ConfigDict
|
|
|
|
|
+
|
|
|
|
|
+ # Initialize backend config
|
|
|
|
|
+ config = ConfigDict()
|
|
|
|
|
+
|
|
|
|
|
+ # Apply HTTP proxy (if configured)
|
|
|
|
|
+ if settings.HTTP_PROXIES and self.url_scheme in ('http', 'https'):
|
|
|
|
|
+ if proxy := settings.HTTP_PROXIES.get(self.url_scheme):
|
|
|
|
|
+ config.set("http", "proxy", proxy)
|
|
|
|
|
+
|
|
|
|
|
+ return config
|
|
|
|
|
+
|
|
|
@contextmanager
|
|
@contextmanager
|
|
|
def fetch(self):
|
|
def fetch(self):
|
|
|
|
|
+ from dulwich import porcelain
|
|
|
|
|
+
|
|
|
local_path = tempfile.TemporaryDirectory()
|
|
local_path = tempfile.TemporaryDirectory()
|
|
|
|
|
|
|
|
- config = ConfigDict()
|
|
|
|
|
clone_args = {
|
|
clone_args = {
|
|
|
"branch": self.params.get('branch'),
|
|
"branch": self.params.get('branch'),
|
|
|
- "config": config,
|
|
|
|
|
|
|
+ "config": self.config,
|
|
|
"depth": 1,
|
|
"depth": 1,
|
|
|
"errstream": porcelain.NoneStream(),
|
|
"errstream": porcelain.NoneStream(),
|
|
|
"quiet": True,
|
|
"quiet": True,
|
|
@@ -110,10 +132,6 @@ class GitBackend(DataBackend):
|
|
|
}
|
|
}
|
|
|
)
|
|
)
|
|
|
|
|
|
|
|
- if settings.HTTP_PROXIES and self.url_scheme in ('http', 'https'):
|
|
|
|
|
- if proxy := settings.HTTP_PROXIES.get(self.url_scheme):
|
|
|
|
|
- config.set("http", "proxy", proxy)
|
|
|
|
|
-
|
|
|
|
|
logger.debug(f"Cloning git repo: {self.url}")
|
|
logger.debug(f"Cloning git repo: {self.url}")
|
|
|
try:
|
|
try:
|
|
|
porcelain.clone(self.url, local_path.name, **clone_args)
|
|
porcelain.clone(self.url, local_path.name, **clone_args)
|
|
@@ -141,15 +159,20 @@ class S3Backend(DataBackend):
|
|
|
|
|
|
|
|
REGION_REGEX = r's3\.([a-z0-9-]+)\.amazonaws\.com'
|
|
REGION_REGEX = r's3\.([a-z0-9-]+)\.amazonaws\.com'
|
|
|
|
|
|
|
|
- @contextmanager
|
|
|
|
|
- def fetch(self):
|
|
|
|
|
- local_path = tempfile.TemporaryDirectory()
|
|
|
|
|
|
|
+ def init_config(self):
|
|
|
|
|
+ from botocore.config import Config as Boto3Config
|
|
|
|
|
|
|
|
- # Build the S3 configuration
|
|
|
|
|
- s3_config = Boto3Config(
|
|
|
|
|
|
|
+ # Initialize backend config
|
|
|
|
|
+ return Boto3Config(
|
|
|
proxies=settings.HTTP_PROXIES,
|
|
proxies=settings.HTTP_PROXIES,
|
|
|
)
|
|
)
|
|
|
|
|
|
|
|
|
|
+ @contextmanager
|
|
|
|
|
+ def fetch(self):
|
|
|
|
|
+ import boto3
|
|
|
|
|
+
|
|
|
|
|
+ local_path = tempfile.TemporaryDirectory()
|
|
|
|
|
+
|
|
|
# Initialize the S3 resource and bucket
|
|
# Initialize the S3 resource and bucket
|
|
|
aws_access_key_id = self.params.get('aws_access_key_id')
|
|
aws_access_key_id = self.params.get('aws_access_key_id')
|
|
|
aws_secret_access_key = self.params.get('aws_secret_access_key')
|
|
aws_secret_access_key = self.params.get('aws_secret_access_key')
|
|
@@ -158,7 +181,7 @@ class S3Backend(DataBackend):
|
|
|
region_name=self._region_name,
|
|
region_name=self._region_name,
|
|
|
aws_access_key_id=aws_access_key_id,
|
|
aws_access_key_id=aws_access_key_id,
|
|
|
aws_secret_access_key=aws_secret_access_key,
|
|
aws_secret_access_key=aws_secret_access_key,
|
|
|
- config=s3_config
|
|
|
|
|
|
|
+ config=self.config
|
|
|
)
|
|
)
|
|
|
bucket = s3.Bucket(self._bucket_name)
|
|
bucket = s3.Bucket(self._bucket_name)
|
|
|
|
|
|