Compare commits

..

27 Commits
0.5.0 ... 0.6.0

Author SHA1 Message Date
d92f991cbe Bump VERSION file 2018-10-31 05:30:43 -07:00
c16f72a2ac Merge pull request #104 from ninech/add-more-seeds
Add seed/initialization scripts for additional resources
2018-10-31 13:27:54 +01:00
2fe139cb3c Reorder device types data 2018-10-31 10:58:42 +01:00
aa68548f41 Add Plaform seeds 2018-10-30 14:22:04 +01:00
a10cd805ae Prefix output messages with appropriate emoji 2018-10-30 10:51:43 +01:00
8b8620864c Replace trademarked names with generic ones 2018-10-30 10:11:05 +01:00
d145e9c719 Comply to README style 2018-10-30 10:07:33 +01:00
a120a95184 Fix initializers 2018-10-16 13:26:23 +02:00
97477556e0 Increase order prefix to 3 digits 2018-10-16 13:26:13 +02:00
7e6edd1bf5 Merge branch 'master' into add-more-seeds 2018-10-16 11:32:41 +02:00
b53e886f8f Handle all associations 2018-10-16 11:05:28 +02:00
63062a2634 Bump VERSION file 2018-10-16 00:38:22 -07:00
2b628b9826 Merge pull request #103 from ninech/permissions
Add permissions to user/group initializers
2018-10-16 09:37:41 +02:00
6cc4c67387 Remove default pop value 2018-10-16 09:12:43 +02:00
ab0ce20971 Update README 2018-10-15 15:15:56 +02:00
90ae5cf01d Add device seeds 2018-10-15 15:15:41 +02:00
ebb7779b5f Add device role seeds 2018-10-15 15:15:23 +02:00
60f7de1898 Add rack seeds 2018-10-15 15:15:09 +02:00
89fddbe0ab Add rack role seeds 2018-10-15 15:14:42 +02:00
a2b08a6ca5 Add device type seeds 2018-10-15 15:14:27 +02:00
86675278ab Add manufacturer seeds 2018-10-15 15:14:11 +02:00
791027f77b Add site seeds 2018-10-15 15:13:51 +02:00
819f325bd5 Add region seeds 2018-10-15 15:13:26 +02:00
4053a714f8 Add permissions to user/group initializers
Thank you @bdlamprecht for researching how to add permissions to
users and groups in #92.

Fixes #92
2018-10-13 17:44:01 +02:00
f1ebd4d246 Merge pull request #101 from ninech/cimnine-ntc-slack
Mention new Network-To-Code #netbox-docker Slack channel
2018-09-27 09:58:52 +02:00
68e6a62df1 Update README.md 2018-09-27 09:44:14 +02:00
81f8c7386d ✏️ Listed one more breaking change 2018-09-14 10:36:09 +02:00
27 changed files with 559 additions and 26 deletions

View File

@ -5,8 +5,11 @@
This repository houses the components needed to build NetBox as a Docker container.
Images built using this code are released to [Docker Hub][netbox-dockerhub] every night.
Questions? Before opening an issue on Github, please join the [Network To Code][ntc-slack] and ask for help in our `#netbox-docker` channel.
[travis]: https://travis-ci.org/ninech/netbox-docker
[netbox-dockerhub]: https://hub.docker.com/r/ninech/netbox/tags/
[ntc-slack]: http://slack.networktocode.com/
## Quickstart
@ -158,7 +161,7 @@ if created:
#### Initializers
Initializers are built-in startup scripts for defining NetBox custom fields, groups and users.
Initializers are built-in startup scripts for defining NetBox custom fields, groups, users and many other resources.
All you need to do is to mount you own `initializers` folder ([see `docker-compose.yml`][netbox-docker-compose]).
Look at the [`initializers` folder][netbox-docker-initializers] to learn how the files must look like.
@ -185,6 +188,15 @@ text_field:
[netbox-docker-initializers]: https://github.com/ninech/netbox-docker/tree/master/initializers
[netbox-docker-compose]: https://github.com/ninech/netbox-docker/blob/master/docker-compose.yml
##### Available Groups for User/Group initializers
To get an up-to-date list about all the available permissions, run the following command.
```bash
# Make sure the 'netbox' container is already running! If unsure, run `docker-compose up -d`
echo "from django.contrib.auth.models import Permission\nfor p in Permission.objects.all():\n print(p.codename);" | docker-compose exec -T netbox ./manage.py shell
```
#### Custom Docker Image
You can also build your own NetBox Docker image containing your own startup scripts, custom fields, users and groups
@ -313,10 +325,10 @@ Then make sure that the `redis` container and at least one `netbox-worker` are r
# check the container status
$ docker-compose ps
Name Command State Ports
Name Command State Ports
--------------------------------------------------------------------------------------------------------
netbox-docker_netbox-worker_1 /opt/netbox/docker-entrypo ... Up
netbox-docker_netbox_1 /opt/netbox/docker-entrypo ... Up
netbox-docker_netbox-worker_1 /opt/netbox/docker-entrypo ... Up
netbox-docker_netbox_1 /opt/netbox/docker-entrypo ... Up
netbox-docker_nginx_1 nginx -c /etc/netbox-nginx ... Up 80/tcp, 0.0.0.0:32776->8080/tcp
netbox-docker_postgres_1 docker-entrypoint.sh postgres Up 5432/tcp
netbox-docker_redis_1 docker-entrypoint.sh redis ... Up 6379/tcp
@ -356,7 +368,7 @@ Compare the version with the list below to check whether a breaking change was i
The following is a list of breaking changes of the `netbox-docker` project:
* 0.5.0: Alpine was updated to 3.8
* 0.5.0: Alpine was updated to 3.8, `*.env` moved to `/env` folder
* 0.4.0: In order to use Netbox webhooks you need to add Redis and a netbox-worker to your docker-compose.yml.
* 0.3.0: Field `filterable: <boolean` was replaced with field `filter_logic: loose/exact/disabled`. It will default to `CF_FILTER_LOOSE=loose` when not defined.
* 0.2.0: Re-organized paths: `/etc/netbox -> /etc/netbox/config` and `/etc/reports -> /etc/netbox/reports`. Fixes [#54](https://github.com/ninech/netbox-docker/issues/54).

View File

@ -1 +1 @@
0.5.0
0.6.0

View File

@ -7,6 +7,8 @@
# on_objects:
# - dcim.models.Device
# - dcim.models.Rack
# - dcim.models.Site
# - dcim.models.DeviceType
# - ipam.models.IPAddress
# - ipam.models.Prefix
# - tenancy.models.Tenant

View File

@ -0,0 +1,15 @@
# - name: switch
# slug: switch
# color: Grey
# - name: router
# slug: router
# color: Cyan
# - name: load-balancer
# slug: load-balancer
# color: Red
# - name: server
# slug: server
# color: Blue
# - name: patchpanel
# slug: patchpanel
# color: Black

View File

@ -0,0 +1,23 @@
# - model: Model 1
# manufacturer: Manufacturer 1
# slug: model-1
# u_height: 2
# custom_fields:
# text_field: Description
# - model: Model 2
# manufacturer: Manufacturer 1
# slug: model-2
# custom_fields:
# text_field: Description
# - model: Model 3
# manufacturer: Manufacturer 1
# slug: model-3
# is_full_depth: false
# u_height: 0
# custom_fields:
# text_field: Description
# - model: Other
# manufacturer: NoName
# slug: other
# custom_fields:
# text_field: Description

27
initializers/devices.yml Normal file
View File

@ -0,0 +1,27 @@
# - name: server01
# device_role: server
# device_type: Other
# site: AMS 1
# rack: rack-01
# face: Front
# position: 1
# custom_fields:
# text_field: Description
# - name: server02
# device_role: server
# device_type: Other
# site: AMS 2
# rack: rack-02
# face: Front
# position: 2
# custom_fields:
# text_field: Description
# - name: server03
# device_role: server
# device_type: Other
# site: SING 1
# rack: rack-03
# face: Front
# position: 3
# custom_fields:
# text_field: Description

View File

@ -7,3 +7,10 @@
# writers:
# users:
# - writer
# permissions:
# - add_device
# - change_device
# - delete_device
# - add_virtualmachine
# - change_virtualmachine
# - delete_virtualmachine

View File

@ -0,0 +1,6 @@
# - name: Manufacturer 1
# slug: manufacturer-1
# - name: Manufacturer 2
# slug: manufacturer-2
# - name: NoName
# slug: noname

View File

@ -0,0 +1,19 @@
# # Allowed rpc clients are: juniper-junos, cisco-ios, opengear
# - name: Platform 1
# slug: platform-1
# manufacturer: Manufacturer 1
# napalm_driver: driver1
# napalm_args: "{'arg1': 'value1', 'arg2': 'value2'}"
# rpc_client: juniper-junos
# - name: Platform 2
# slug: platform-2
# manufacturer: Manufacturer 2
# napalm_driver: driver2
# napalm_args: "{'arg1': 'value1', 'arg2': 'value2'}"
# rpc_client: opengear
# - name: Platform 3
# slug: platform-3
# manufacturer: NoName
# napalm_driver: driver3
# napalm_args: "{'arg1': 'value1', 'arg2': 'value2'}"
# rpc_client: juniper-junos

View File

@ -0,0 +1,12 @@
# - name: Role 1
# slug: role-1
# color: Pink
# - name: Role 2
# slug: role-2
# color: Cyan
# - name: Role 3
# slug: role-3
# color: Grey
# - name: Role 4
# slug: role-4
# color: Teal

24
initializers/racks.yml Normal file
View File

@ -0,0 +1,24 @@
# - site: AMS 1
# name: rack-01
# role: Role 1
# type: 4-post cabinet
# width: 19 inches
# u_height: 47
# custom_fields:
# text_field: Description
# - site: AMS 2
# name: rack-02
# role: Role 2
# type: 4-post cabinet
# width: 19 inches
# u_height: 47
# custom_fields:
# text_field: Description
# - site: SING 1
# name: rack-03
# role: Role 3
# type: 4-post cabinet
# width: 19 inches
# u_height: 47
# custom_fields:
# text_field: Description

10
initializers/regions.yml Normal file
View File

@ -0,0 +1,10 @@
# - name: Singapore
# slug: singapore
# - name: Amsterdam
# slug: amsterdam
# - name: Downtown
# slug: downtown
# parent: Amsterdam
# - name: Suburbs
# slug: suburbs
# parent: Amsterdam

32
initializers/sites.yml Normal file
View File

@ -0,0 +1,32 @@
# - name: AMS 1
# slug: ams1
# region: Downtown
# status: 1
# facility: Amsterdam 1
# asn: 12345
# custom_fields:
# text_field: Description
# - name: AMS 2
# slug: ams2
# region: Downtown
# status: 1
# facility: Amsterdam 2
# asn: 54321
# custom_fields:
# text_field: Description
# - name: AMS 3
# slug: ams3
# region: Suburbs
# status: 1
# facility: Amsterdam 3
# asn: 67890
# custom_fields:
# text_field: Description
# - name: SING 1
# slug: sing1
# region: Singapore
# status: 1
# facility: Singapore 1
# asn: 09876
# custom_fields:
# text_field: Description

View File

@ -4,3 +4,10 @@
# password: reader
# writer:
# password: writer
# permissions:
# - add_device
# - change_device
# - delete_device
# - add_virtualmachine
# - change_virtualmachine
# - delete_virtualmachine

View File

@ -1,4 +1,4 @@
from django.contrib.auth.models import Group, User
from django.contrib.auth.models import Permission, Group, User
from users.models import Token
from ruamel.yaml import YAML
@ -18,3 +18,11 @@ with open('/opt/netbox/initializers/users.yml', 'r') as stream:
if user_details.get('api_token', 0):
Token.objects.create(user=user, key=user_details['api_token'])
user_permissions = user_details.get('permissions', [])
if user_permissions:
user.user_permissions.clear()
for permission_codename in user_details.get('permissions', []):
permission = Permission.objects.get(codename=permission_codename)
user.user_permissions.add(permission)
user.save()

View File

@ -0,0 +1,27 @@
from django.contrib.auth.models import Permission, Group, User
from ruamel.yaml import YAML
with open('/opt/netbox/initializers/groups.yml', 'r') as stream:
yaml=YAML(typ='safe')
groups = yaml.load(stream)
if groups is not None:
for groupname, group_details in groups.items():
group, created = Group.objects.get_or_create(name=groupname)
if created:
print("👥 Created group", groupname)
for username in group_details.get('users', []):
user = User.objects.get(username=username)
if user:
user.groups.add(group)
group_permissions = group_details.get('permissions', [])
if group_permissions:
group.permissions.clear()
print("Permissions:", group.permissions.all())
for permission_codename in group_details.get('permissions', []):
permission = Permission.objects.get(codename=permission_codename)
group.permissions.add(permission)

View File

@ -0,0 +1,25 @@
from dcim.models import Region
from ruamel.yaml import YAML
with open('/opt/netbox/initializers/regions.yml', 'r') as stream:
yaml=YAML(typ='safe')
regions = yaml.load(stream)
optional_assocs = {
'parent': (Region, 'name')
}
if regions is not None:
for params in regions:
for assoc, details in optional_assocs.items():
if assoc in params:
model, field = details
query = { field: params.pop(assoc) }
params[assoc] = model.objects.get(**query)
region, created = Region.objects.get_or_create(**params)
if created:
print("🌐 Created region", region.name)

View File

@ -0,0 +1,40 @@
from dcim.models import Region, Site
from extras.models import CustomField, CustomFieldValue
from tenancy.models import Tenant
from ruamel.yaml import YAML
with open('/opt/netbox/initializers/sites.yml', 'r') as stream:
yaml = YAML(typ='safe')
sites = yaml.load(stream)
optional_assocs = {
'region': (Region, 'name'),
'tenant': (Tenant, 'name')
}
if sites is not None:
for params in sites:
custom_fields = params.pop('custom_fields', None)
for assoc, details in optional_assocs.items():
if assoc in params:
model, field = details
query = { field: params.pop(assoc) }
params[assoc] = model.objects.get(**query)
site, created = Site.objects.get_or_create(**params)
if created:
if custom_fields is not None:
for cf_name, cf_value in custom_fields.items():
custom_field = CustomField.objects.get(name=cf_name)
custom_field_value = CustomFieldValue.objects.create(
field=custom_field,
obj=site,
value=cf_value
)
site.custom_field_values.add(custom_field_value)
print("📍 Created site", site.name)

View File

@ -0,0 +1,13 @@
from dcim.models import Manufacturer
from ruamel.yaml import YAML
with open('/opt/netbox/initializers/manufacturers.yml', 'r') as stream:
yaml = YAML(typ='safe')
manufacturers = yaml.load(stream)
if manufacturers is not None:
for params in manufacturers:
manufacturer, created = Manufacturer.objects.get_or_create(**params)
if created:
print("🏭 Created Manufacturer", manufacturer.name)

View File

@ -0,0 +1,51 @@
from dcim.models import DeviceType, Manufacturer, Region
from tenancy.models import Tenant
from extras.models import CustomField, CustomFieldValue
from ruamel.yaml import YAML
with open('/opt/netbox/initializers/device_types.yml', 'r') as stream:
yaml = YAML(typ='safe')
device_types = yaml.load(stream)
required_assocs = {
'manufacturer': (Manufacturer, 'name')
}
optional_assocs = {
'region': (Region, 'name'),
'tenant': (Tenant, 'name')
}
if device_types is not None:
for params in device_types:
custom_fields = params.pop('custom_fields', None)
for assoc, details in required_assocs.items():
model, field = details
query = { field: params.pop(assoc) }
params[assoc] = model.objects.get(**query)
for assoc, details in optional_assocs.items():
if assoc in params:
model, field = details
query = { field: params.pop(assoc) }
params[assoc] = model.objects.get(**query)
device_type, created = DeviceType.objects.get_or_create(**params)
if created:
if custom_fields is not None:
for cf_name, cf_value in custom_fields.items():
custom_field = CustomField.objects.get(name=cf_name)
custom_field_value = CustomFieldValue.objects.create(
field=custom_field,
obj=device_type,
value=cf_value
)
device_type.custom_field_values.add(custom_field_value)
print("🔡 Created device type", device_type.manufacturer, device_type.model)

View File

@ -0,0 +1,21 @@
from dcim.models import RackRole
from ruamel.yaml import YAML
from utilities.forms import COLOR_CHOICES
with open('/opt/netbox/initializers/rack_roles.yml', 'r') as stream:
yaml=YAML(typ='safe')
rack_roles = yaml.load(stream)
if rack_roles is not None:
for params in rack_roles:
if 'color' in params:
color = params.pop('color')
for color_tpl in COLOR_CHOICES:
if color in color_tpl:
params['color'] = color_tpl[0]
rack_role, created = RackRole.objects.get_or_create(**params)
if created:
print("🎨 Created rack role", rack_role.name)

View File

@ -0,0 +1,60 @@
from dcim.models import Site, RackRole, Rack, RackGroup
from tenancy.models import Tenant
from extras.models import CustomField, CustomFieldValue
from dcim.constants import RACK_TYPE_CHOICES, RACK_WIDTH_CHOICES
from ruamel.yaml import YAML
with open('/opt/netbox/initializers/racks.yml', 'r') as stream:
yaml = YAML(typ='safe')
racks = yaml.load(stream)
required_assocs = {
'site': (Site, 'name')
}
optional_assocs = {
'role': (RackRole, 'name'),
'tenant': (Tenant, 'name'),
'group': (RackGroup, 'name')
}
if racks is not None:
for params in racks:
custom_fields = params.pop('custom_fields', None)
for assoc, details in required_assocs.items():
model, field = details
query = { field: params.pop(assoc) }
params[assoc] = model.objects.get(**query)
for assoc, details in optional_assocs.items():
if assoc in params:
model, field = details
query = { field: params.pop(assoc) }
params[assoc] = model.objects.get(**query)
for rack_type in RACK_TYPE_CHOICES:
if params['type'] in rack_type:
params['type'] = rack_type[0]
for rack_width in RACK_WIDTH_CHOICES:
if params['width'] in rack_width:
params['width'] = rack_width[0]
rack, created = Rack.objects.get_or_create(**params)
if created:
if custom_fields is not None:
for cf_name, cf_value in custom_fields.items():
custom_field = CustomField.objects.get(name=cf_name)
custom_field_value = CustomFieldValue.objects.create(
field=custom_field,
obj=rack,
value=cf_value
)
rack.custom_field_values.add(custom_field_value)
print("🔳 Created rack", rack.site, rack.name)

View File

@ -0,0 +1,22 @@
from dcim.models import DeviceRole
from ruamel.yaml import YAML
from utilities.forms import COLOR_CHOICES
with open('/opt/netbox/initializers/device_roles.yml', 'r') as stream:
yaml=YAML(typ='safe')
device_roles = yaml.load(stream)
if device_roles is not None:
for params in device_roles:
if 'color' in params:
color = params.pop('color')
for color_tpl in COLOR_CHOICES:
if color in color_tpl:
params['color'] = color_tpl[0]
device_role, created = DeviceRole.objects.get_or_create(**params)
if created:
print("🎨 Created device role", device_role.name)

View File

@ -0,0 +1,25 @@
from dcim.models import Manufacturer, Platform
from ruamel.yaml import YAML
with open('/opt/netbox/initializers/platforms.yml', 'r') as stream:
yaml = YAML(typ='safe')
platforms = yaml.load(stream)
optional_assocs = {
'manufacturer': (Manufacturer, 'name'),
}
if platforms is not None:
for params in platforms:
for assoc, details in optional_assocs.items():
if assoc in params:
model, field = details
query = { field: params.pop(assoc) }
params[assoc] = model.objects.get(**query)
platform, created = Platform.objects.get_or_create(**params)
if created:
print("💾 Created platform", platform.name)

View File

@ -1,19 +0,0 @@
from django.contrib.auth.models import Group, User
from ruamel.yaml import YAML
with open('/opt/netbox/initializers/groups.yml', 'r') as stream:
yaml=YAML(typ='safe')
groups = yaml.load(stream)
if groups is not None:
for groupname, group_details in groups.items():
group, created = Group.objects.get_or_create(name=groupname)
if created:
print("👥 Created group", groupname)
for username in group_details['users']:
user = User.objects.get(username=username)
if user:
user.groups.add(group)

View File

@ -0,0 +1,64 @@
from dcim.models import Site, Rack, DeviceRole, DeviceType, Device, Platform
from dcim.constants import RACK_FACE_CHOICES
from ipam.models import IPAddress
from virtualization.models import Cluster
from tenancy.models import Tenant
from extras.models import CustomField, CustomFieldValue
from ruamel.yaml import YAML
with open('/opt/netbox/initializers/devices.yml', 'r') as stream:
yaml = YAML(typ='safe')
devices = yaml.load(stream)
required_assocs = {
'device_role': (DeviceRole, 'name'),
'device_type': (DeviceType, 'model'),
'site': (Site, 'name')
}
optional_assocs = {
'tenant': (Tenant, 'name'),
'platform': (Platform, 'name'),
'rack': (Rack, 'name'),
'cluster': (Cluster, 'name'),
'primary_ip4': (IPAddress, 'address'),
'primary_ip6': (IPAddress, 'address')
}
if devices is not None:
for params in devices:
custom_fields = params.pop('custom_fields', None)
for assoc, details in required_assocs.items():
model, field = details
query = { field: params.pop(assoc) }
params[assoc] = model.objects.get(**query)
for assoc, details in optional_assocs.items():
if assoc in params:
model, field = details
query = { field: params.pop(assoc) }
params[assoc] = model.objects.get(**query)
if 'face' in params:
for rack_face in RACK_FACE_CHOICES:
if params['face'] in rack_face:
params['face'] = rack_face[0]
device, created = Device.objects.get_or_create(**params)
if created:
if custom_fields is not None:
for cf_name, cf_value in custom_fields.items():
custom_field = CustomField.objects.get(name=cf_name)
custom_field_value = CustomFieldValue.objects.create(
field=custom_field,
obj=device,
value=cf_value
)
device.custom_field_values.add(custom_field_value)
print("🖥️ Created device", device.name)