Skip to content

Commit cacc418

Browse files
Closes: #11781: Add support for Amazon S3 remote data sources (#11986)
* Add boto3 as a dependency * Add Amazon S3 backend for remote data sources * Update docs to include Amazon S3 support
1 parent 5cd3ad0 commit cacc418

File tree

6 files changed

+86
-5
lines changed

6 files changed

+86
-5
lines changed

base_requirements.txt

+4
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22
# https://github.com/mozilla/bleach
33
bleach<6.0
44

5+
# Python client for Amazon AWS API
6+
# https://github.com/boto/boto3
7+
boto3
8+
59
# The Python web framework on which NetBox is built
610
# https://github.com/django/django
711
Django<4.2

docs/models/core/datasource.md

+6-4
Original file line numberDiff line numberDiff line change
@@ -14,15 +14,17 @@ The type of data source. Supported options include:
1414

1515
* Local directory
1616
* git repository
17+
* Amazon S3 bucket
1718

1819
### URL
1920

2021
The URL identifying the remote source. Some examples are included below.
2122

22-
| Type | Example URL |
23-
|------|-------------|
24-
| Local | file:///var/my/data/source/ |
25-
| git | https://https://github.com/my-organization/my-repo |
23+
| Type | Example URL |
24+
|-----------|----------------------------------------------------|
25+
| Local | file:///path/to/my/data/ |
26+
| git | https://github.com/my-organization/my-repo |
27+
| Amazon S3 | https://s3.us-east-2.amazonaws.com/my-bucket-name/ |
2628

2729
### Status
2830

docs/release-notes/version-3.5.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ The static home view has been replaced with a fully customizable dashboard. User
1010

1111
#### Remote Data Sources ([#11558](https://github.com/netbox-community/netbox/issues/11558))
1212

13-
NetBox now has the ability to synchronize arbitrary data from external sources through the new [DataSource](../models/core/datasource.md) and [DataFile](../models/core/datafile.md) models. Synchronized files are stored in the PostgreSQL database, and may be referenced and consumed by other NetBox models, such as export templates and config contexts. Currently, replication from local filesystem paths and from git repositories is supported, and we expect to add support for additional backends in the near future.
13+
NetBox now has the ability to synchronize arbitrary data from external sources through the new [DataSource](../models/core/datasource.md) and [DataFile](../models/core/datafile.md) models. Synchronized files are stored in the PostgreSQL database, and may be referenced and consumed by other NetBox models, such as export templates and config contexts. Currently, replication from local filesystem paths, git repositories, and Amazon S3 buckets is supported, and we expect to introduce additional backends in the near future.
1414

1515
#### Configuration Template Rendering ([#11559](https://github.com/netbox-community/netbox/issues/11559))
1616

netbox/core/choices.py

+2
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,12 @@
1010
class DataSourceTypeChoices(ChoiceSet):
1111
LOCAL = 'local'
1212
GIT = 'git'
13+
AMAZON_S3 = 'amazon-s3'
1314

1415
CHOICES = (
1516
(LOCAL, _('Local'), 'gray'),
1617
(GIT, _('Git'), 'blue'),
18+
(AMAZON_S3, _('Amazon S3'), 'blue'),
1719
)
1820

1921

netbox/core/data_backends.py

+72
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,14 @@
11
import logging
2+
import os
3+
import re
24
import subprocess
35
import tempfile
46
from contextlib import contextmanager
7+
from pathlib import Path
58
from urllib.parse import quote, urlunparse, urlparse
69

10+
import boto3
11+
from botocore.config import Config as Boto3Config
712
from django import forms
813
from django.conf import settings
914
from django.utils.translation import gettext as _
@@ -115,3 +120,70 @@ def fetch(self):
115120
yield local_path.name
116121

117122
local_path.cleanup()
123+
124+
125+
@register_backend(DataSourceTypeChoices.AMAZON_S3)
126+
class S3Backend(DataBackend):
127+
parameters = {
128+
'aws_access_key_id': forms.CharField(
129+
label=_('AWS access key ID'),
130+
widget=forms.TextInput(attrs={'class': 'form-control'})
131+
),
132+
'aws_secret_access_key': forms.CharField(
133+
label=_('AWS secret access key'),
134+
widget=forms.TextInput(attrs={'class': 'form-control'})
135+
),
136+
}
137+
138+
REGION_REGEX = r's3\.([a-z0-9-]+)\.amazonaws\.com'
139+
140+
@contextmanager
141+
def fetch(self):
142+
local_path = tempfile.TemporaryDirectory()
143+
144+
# Build the S3 configuration
145+
s3_config = Boto3Config(
146+
proxies=settings.HTTP_PROXIES,
147+
)
148+
149+
# Initialize the S3 resource and bucket
150+
aws_access_key_id = self.params.get('aws_access_key_id')
151+
aws_secret_access_key = self.params.get('aws_secret_access_key')
152+
s3 = boto3.resource(
153+
's3',
154+
region_name=self._region_name,
155+
aws_access_key_id=aws_access_key_id,
156+
aws_secret_access_key=aws_secret_access_key,
157+
config=s3_config
158+
)
159+
bucket = s3.Bucket(self._bucket_name)
160+
161+
# Download all files within the specified path
162+
for obj in bucket.objects.filter(Prefix=self._remote_path):
163+
local_filename = os.path.join(local_path.name, obj.key)
164+
# Build local path
165+
Path(os.path.dirname(local_filename)).mkdir(parents=True, exist_ok=True)
166+
bucket.download_file(obj.key, local_filename)
167+
168+
yield local_path.name
169+
170+
local_path.cleanup()
171+
172+
@property
173+
def _region_name(self):
174+
domain = urlparse(self.url).netloc
175+
if m := re.match(self.REGION_REGEX, domain):
176+
return m.group(1)
177+
return None
178+
179+
@property
180+
def _bucket_name(self):
181+
url_path = urlparse(self.url).path.lstrip('/')
182+
return url_path.split('/')[0]
183+
184+
@property
185+
def _remote_path(self):
186+
url_path = urlparse(self.url).path.lstrip('/')
187+
if '/' in url_path:
188+
return url_path.split('/', 1)[1]
189+
return ''

requirements.txt

+1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
bleach==5.0.1
2+
boto3==1.26.91
23
Django==4.1.7
34
django-cors-headers==3.14.0
45
django-debug-toolbar==3.8.1

0 commit comments

Comments
 (0)