From cf0fd8f04f4cd13bc8dfab88fd0e43fbe4cc049e Mon Sep 17 00:00:00 2001 From: Omar Morales Date: Wed, 11 Jun 2025 13:38:59 -0700 Subject: [PATCH 01/26] update configuration.py template --- templates/configuration.py.epp | 94 +++++++++++++++++++++++++++++++--- 1 file changed, 87 insertions(+), 7 deletions(-) diff --git a/templates/configuration.py.epp b/templates/configuration.py.epp index dbf3c47..eebce4d 100644 --- a/templates/configuration.py.epp +++ b/templates/configuration.py.epp @@ -1,5 +1,6 @@ <% | Array[Stdlib::Host] $allowed_hosts, + Boolean $allow_api_token_retrieval, String $database_name, String $database_user, String $database_password, @@ -30,6 +31,11 @@ String $short_time_format, String $datetime_format, String $short_datetime_format, + String $remote_auth_backend, + String $remote_auth_header, + String $remote_auth_first_name, + String $remote_auth_last_name, + String $remote_auth_user_email, | -%> ######################### @@ -46,13 +52,16 @@ ALLOWED_HOSTS = ['<%=$allowed_hosts.join("\',\'")%>'] # PostgreSQL database configuration. See the Django documentation for a complete list of available parameters: # https://docs.djangoproject.com/en/stable/ref/settings/#databases -DATABASE = { - 'NAME': '<%=$database_name%>', # Database name - 'USER': '<%=$database_user%>', # PostgreSQL username - 'PASSWORD': '<%=$database_password%>', # PostgreSQL password - 'HOST': '<%=$database_host%>', # Database server - 'PORT': <%=$database_port%>, # Database port (leave blank for default) - 'CONN_MAX_AGE': <%=$database_conn_max_age%>, # Max database connection age +DATABASES = { + 'default':{ + 'ENGINE': 'django.db.backends.postgresql', # Database engine + 'NAME': '<%=$database_name%>', # Database name + 'USER': '<%=$database_user%>', # PostgreSQL username + 'PASSWORD': '<%=$database_password%>', # PostgreSQL password + 'HOST': '<%=$database_host%>', # Database server + 'PORT': <%=$database_port%>, # Database port (leave blank for default) + 'CONN_MAX_AGE': <%=$database_conn_max_age%>, # Max database connection age + } } # Redis database settings. The Redis database is used for caching and background processing such as webhooks @@ -103,6 +112,20 @@ ADMINS = [ <%= $admins.map |$v| { String([$v['name'], $v['email']])}.join(",\n ") %> ] +# Permit the retrieval of API tokens after their creation. +ALLOW_TOKEN_RETRIEVAL = <%=$allow_api_token_retrieval%> + +# Enable any desired validators for local account passwords below. For a list of included validators, please see the +# Django documentation at https://docs.djangoproject.com/en/stable/topics/auth/passwords/#password-validation. +AUTH_PASSWORD_VALIDATORS = [ + # { + # 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', + # 'OPTIONS': { + # 'min_length': 10, + # } + # }, +] + # Optionally display a persistent banner at the top and/or bottom of every page. HTML is allowed. To display the same # content in both banners, define BANNER_TOP and set BANNER_BOTTOM = BANNER_TOP. BANNER_TOP = '<%= $banner_top %>' @@ -132,6 +155,9 @@ CORS_ORIGIN_REGEX_WHITELIST = [ # r'^(https?://)?(\w+\.)?example\.com$', ] +# The name to use for the CSRF token cookie. +CSRF_COOKIE_NAME = 'csrftoken' + # Set to True to enable server debugging. WARNING: Debugging introduces a substantial performance penalty and may reveal # sensitive information about your installation. Only enable debugging while performing testing. Never enable debugging # on a production system. @@ -141,6 +167,9 @@ DEBUG = True DEBUG = False <% } -%> +# Set the default preferred language/locale +DEFAULT_LANGUAGE = 'en-us' + # Email settings # https://netbox.readthedocs.io/en/stable/configuration/optional-settings/#email EMAIL = { @@ -148,6 +177,8 @@ EMAIL = { 'PORT': <%=$email_options['port']%>, 'USERNAME': '<%=$email_options['username']%>', 'PASSWORD': '<%=$email_options['password']%>', + 'USE_SSL': <%=$email_options['ssl']%>, + 'USE_TLS': <%=$email_options['tls']%>, 'TIMEOUT': <%=$email_options['timeout']%>, # seconds 'FROM_EMAIL': '<%=$email_options['from_email']%>', } @@ -166,10 +197,18 @@ EXEMPT_VIEW_PERMISSIONS = [ <%= $exempt_view_permissions.join(",\n ") %> ] +# IP addresses recognized as internal to the system. The debugging toolbar will be available only to clients accessing +# NetBox from an internal IP. +INTERNAL_IPS = ('127.0.0.1', '::1') + # Enable custom logging. Please see the Django documentation for detailed guidance on configuring custom logs: # https://docs.djangoproject.com/en/stable/topics/logging/ LOGGING = {} +# Automatically reset the lifetime of a valid session upon each authenticated request. Enables users to remain +# authenticated to NetBox indefinitely. +LOGIN_PERSISTENCE = False + # Setting this to True will permit only authenticated users to access any part of NetBox. By default, anonymous users # are permitted to access most data in NetBox (excluding secrets) but not make any changes. <% if $login_required { -%> @@ -182,6 +221,12 @@ LOGIN_REQUIRED = False # re-authenticate. (Default: 1209600 [14 days]) LOGIN_TIMEOUT = None +# Hide the login form. Useful when only allowing SSO authentication. +LOGIN_FORM_HIDDEN = False + +# The view name or URL to which users are redirected after logging out. +LOGOUT_REDIRECT_URL = 'home' + # Setting this to True will display a "maintenance mode" banner at the top of every page. MAINTENANCE_MODE = False @@ -225,6 +270,18 @@ NAPALM_ARGS = {} # Determine how many objects to display per page within a list. (Default: 50) PAGINATE_COUNT = 50 +# Enable installed plugins. Add the name of each plugin to the list. +PLUGINS = [] + +# Plugins configuration settings. These settings are used by various plugins that the user may have installed. +# Each key in the dictionary is the name of an installed plugin and its value is a dictionary of settings. +# PLUGINS_CONFIG = { +# 'my_plugin': { +# 'foo': 'bar', +# 'buzz': 'bazz' +# } +# } + # When determining the primary IP address for a device, IPv6 is preferred over IPv4 by default. Set this to True to # prefer IPv4 instead. <% if $prefer_ipv4 { -%> @@ -233,6 +290,29 @@ PREFER_IPV4 = True PREFER_IPV4 = False <% } -%> +# Remote authentication support +REMOTE_AUTH_ENABLED = <%=$remote_auth_enabled%> +REMOTE_AUTH_BACKEND = '<%=$remote_auth_backend%>' +REMOTE_AUTH_HEADER = '<%=$remote_auth_header%>' +REMOTE_AUTH_USER_FIRST_NAME = '<%=$remote_auth_first_name%>' +REMOTE_AUTH_USER_LAST_NAME = '<%=$remote_auth_last_name%>' +REMOTE_AUTH_USER_EMAIL = '<%=$remote_auth_user_email%>' +REMOTE_AUTH_AUTO_CREATE_USER = True +REMOTE_AUTH_DEFAULT_GROUPS = [] +REMOTE_AUTH_DEFAULT_PERMISSIONS = {} + +# This repository is used to check whether there is a new release of NetBox available. Set to None to disable the +# version check or use the URL below to check for release in the official NetBox repository. +RELEASE_CHECK_URL = None +# RELEASE_CHECK_URL = 'https://api.github.com/repos/netbox-community/netbox/releases' + +# The file path where custom reports will be stored. A trailing slash is not needed. Note that the default value of +# this setting is derived from the installed location. +# REPORTS_ROOT = '/opt/netbox/netbox/reports' + +# Maximum execution time for background tasks, in seconds. +RQ_DEFAULT_TIMEOUT = 300 + # The file path where custom reports will be stored. A trailing slash is not needed. Note that the default value of # this setting is derived from the installed location. # REPORTS_ROOT = '/opt/netbox/netbox/reports' From 971736fb1a70c1bdc1592b26b4d18c512f87dd85 Mon Sep 17 00:00:00 2001 From: Omar Morales Date: Wed, 11 Jun 2025 15:38:19 -0700 Subject: [PATCH 02/26] update ldap_config.py template --- templates/ldap_config.py.epp | 31 +++++++++++++++++++------------ 1 file changed, 19 insertions(+), 12 deletions(-) diff --git a/templates/ldap_config.py.epp b/templates/ldap_config.py.epp index 5726d0b..943c8d3 100644 --- a/templates/ldap_config.py.epp +++ b/templates/ldap_config.py.epp @@ -1,10 +1,17 @@ <% | + String $ldap_sever_uri, + String $ad_ou, + String $ad_bind_cn, + String $ad_require_cn, + String $ldap_bind_password, + Boolean $ldap_ignore_cert_errors, + Boolean $ldap_mirror_groups, | -%> import ldap from django_auth_ldap.config import LDAPSearch, GroupOfNamesType # Server URI -AUTH_LDAP_SERVER_URI = "ldaps://ad.example.com" +AUTH_LDAP_SERVER_URI = '<%=$ldap_sever_uri%>' # The following may be needed if you are binding to Active Directory. AUTH_LDAP_CONNECTION_OPTIONS = { @@ -12,22 +19,22 @@ AUTH_LDAP_CONNECTION_OPTIONS = { } # Set the DN and password for the NetBox service account. -AUTH_LDAP_BIND_DN = "CN=NETBOXSA, OU=Service Accounts,DC=example,DC=com" -AUTH_LDAP_BIND_PASSWORD = "demo" +AUTH_LDAP_BIND_DN = "<%=$ad_bind_cn%>,OU=Service Accounts,<%=$ad_ou%>" +AUTH_LDAP_BIND_PASSWORD = "<%=$ldap_bind_password%>" # Include this setting if you want to ignore certificate errors. This might be needed to accept a self-signed cert. # Note that this is a NetBox-specific setting which sets: # ldap.set_option(ldap.OPT_X_TLS_REQUIRE_CERT, ldap.OPT_X_TLS_NEVER) -LDAP_IGNORE_CERT_ERRORS = True +LDAP_IGNORE_CERT_ERRORS = <%=$ldap_ignore_cert_errors%> # This search matches users with the sAMAccountName equal to the provided username. This is required if the user's # username is not in their DN (Active Directory). -AUTH_LDAP_USER_SEARCH = LDAPSearch("ou=Users,dc=example,dc=com", +AUTH_LDAP_USER_SEARCH = LDAPSearch("<%=$ad_ou%>", ldap.SCOPE_SUBTREE, "(sAMAccountName=%(user)s)") # If a user's DN is producible from their username, we don't need to search. -AUTH_LDAP_USER_DN_TEMPLATE = "uid=%(user)s,ou=users,dc=example,dc=com" +AUTH_LDAP_USER_DN_TEMPLATE = "uid=%(user)s,ou=users,<%=$ad_ou%>" # You can map user attributes to Django attributes as so. AUTH_LDAP_USER_ATTR_MAP = { @@ -38,21 +45,21 @@ AUTH_LDAP_USER_ATTR_MAP = { # This search ought to return all groups to which the user belongs. django_auth_ldap uses this to determine group # hierarchy. -AUTH_LDAP_GROUP_SEARCH = LDAPSearch("dc=example,dc=com", ldap.SCOPE_SUBTREE, +AUTH_LDAP_GROUP_SEARCH = LDAPSearch("<%=$ad_ou%>", ldap.SCOPE_SUBTREE, "(objectClass=group)") AUTH_LDAP_GROUP_TYPE = GroupOfNamesType() # Define a group required to login. -AUTH_LDAP_REQUIRE_GROUP = "CN=NETBOX_USERS,DC=example,DC=com" +AUTH_LDAP_REQUIRE_GROUP = "<%=$ad_require_cn%>,<%=$ad_ou%>" # Mirror LDAP group assignments. -AUTH_LDAP_MIRROR_GROUPS = True +AUTH_LDAP_MIRROR_GROUPS = <%=$ldap_mirror_groups%> # Define special user types using groups. Exercise great caution when assigning superuser status. AUTH_LDAP_USER_FLAGS_BY_GROUP = { - "is_active": "cn=active,ou=groups,dc=example,dc=com", - "is_staff": "cn=staff,ou=groups,dc=example,dc=com", - "is_superuser": "cn=superuser,ou=groups,dc=example,dc=com" + "is_active": "cn=active,ou=groups,<%=$ad_ou%>", + "is_staff": "cn=staff,ou=groups,<%=$ad_ou%>", + "is_superuser": "cn=superuser,ou=groups,<%=$ad_ou%>" } # For more granular permissions, we can map LDAP groups to Django groups. From 224ced556b873a80d3ac35fe615e630d4bf8f705 Mon Sep 17 00:00:00 2001 From: Omar Morales Date: Wed, 11 Jun 2025 16:25:28 -0700 Subject: [PATCH 03/26] update config.pp --- manifests/config.pp | 109 +++++++++++++++++++++++++++++++------------- 1 file changed, 78 insertions(+), 31 deletions(-) diff --git a/manifests/config.pp b/manifests/config.pp index e9ce50e..8722fca 100644 --- a/manifests/config.pp +++ b/manifests/config.pp @@ -17,6 +17,9 @@ # Array of valid fully-qualified domain names (FQDNs) for the NetBox server. NetBox will not permit write # access to the server via any other hostnames. The first FQDN in the list will be treated as the preferred name. # +# @param allow_token_retrieval +# Permit the retrieval of API tokens after their creation. +# # @param database_name # Name of the PostgreSQL database. If handle_database is true, then this database # gets created as well. If not, then it is only used by the application, and needs to exist. @@ -132,6 +135,36 @@ # Date/time formatting. See the following link for supported formats: # https://docs.djangoproject.com/en/stable/ref/templates/builtins/#date # +# @param remote_auth_enabled +# boolean that enables the remote authentication for netbox. +# This must be set to True in order for remote_auth_* settings to take effect. +# +# @param remote_auth_backend +# This is the Python path to the custom Django authentication backend to use for external +# user authentication. NetBox provides two built-in backends (listed below), though custom +# authentication backends may also be provided by other packages or plugins. Provide a string +# for a single backend, or an iterable for multiple backends, which will be attempted in the order given. +# +# @param remote_auth_header +# When remote user authentication is in use, this is the name of the HTTP header which informs +# NetBox of the currently authenticated user. For example, to use the request header X-Remote-User +# it needs to be set to HTTP_X_REMOTE_USER +# +# @param remote_auth_first_name +# When remote user authentication is in use, this is the name of the HTTP header which informs +# NetBox of the first name of the currently authenticated user. For example, to use the request +# header X-Remote-User-First-Name it needs to be set to HTTP_X_REMOTE_USER_FIRST_NAME. +# +# @param remote_auth_last_name +# When remote user authentication is in use, this is the name of the HTTP header which informs +# NetBox of the last name of the currently authenticated user. For example, to use the request +# header X-Remote-User-Last-Name it needs to be set to HTTP_X_REMOTE_USER_LAST_NAME. +# +# @param remote_auth_user_email +# When remote user authentication is in use, this is the name of the HTTP header which informs +# NetBox of the email address of the currently authenticated user. For example, to use the request +# header X-Remote-User-Email it needs to be set to HTTP_X_REMOTE_USER_EMAIL. +# # @example # include netbox::config class netbox::config ( @@ -139,6 +172,7 @@ String $group, Stdlib::Absolutepath $install_root, Array[Stdlib::Host] $allowed_hosts, + Boolean $allow_api_token_retrieval, String $database_name, String $database_user, String $database_password, @@ -169,6 +203,12 @@ String $short_time_format, String $datetime_format, String $short_datetime_format, + Boolean $remote_auth_enabled, + String $remote_auth_backend, + String $remote_auth_header, + String $remote_auth_first_name, + String $remote_auth_last_name, + String $remote_auth_user_email, ) { $should_create_superuser = false; $software_directory = "${install_root}/netbox" @@ -195,37 +235,44 @@ file { $config_file: content => epp('netbox/configuration.py.epp', { - 'allowed_hosts' => $allowed_hosts, - 'database_name' => $database_name, - 'database_user' => $database_user, - 'database_password' => $database_password, - 'database_host' => $database_host, - 'database_port' => $database_port, - 'database_conn_max_age' => $database_conn_max_age, - 'redis_options' => $redis_options, - 'email_options' => $email_options, - 'secret_key' => $secret_key, - 'admins' => $admins, - 'banner_top' => $banner_top, - 'banner_bottom' => $banner_bottom, - 'banner_login' => $banner_login, - 'base_path' => $base_path, - 'debug' => $debug, - 'enforce_global_unique' => $enforce_global_unique, - 'exempt_view_permissions' => $exempt_view_permissions, - 'login_required' => $login_required, - 'metrics_enabled' => $metrics_enabled, - 'prefer_ipv4' => $prefer_ipv4, - 'napalm_username' => $napalm_username, - 'napalm_password' => $napalm_password, - 'napalm_timeout' => $napalm_timeout, - 'time_zone' => $time_zone, - 'date_format' => $date_format, - 'short_date_format' => $short_date_format, - 'time_format' => $time_format, - 'short_time_format' => $short_time_format, - 'datetime_format' => $datetime_format, - 'short_datetime_format' => $short_datetime_format, + 'allowed_hosts' => $allowed_hosts, + 'allow_api_token_retrieval' => $allow_api_token_retrieval, + 'database_name' => $database_name, + 'database_user' => $database_user, + 'database_password' => $database_password, + 'database_host' => $database_host, + 'database_port' => $database_port, + 'database_conn_max_age' => $database_conn_max_age, + 'redis_options' => $redis_options, + 'email_options' => $email_options, + 'secret_key' => $secret_key, + 'admins' => $admins, + 'banner_top' => $banner_top, + 'banner_bottom' => $banner_bottom, + 'banner_login' => $banner_login, + 'base_path' => $base_path, + 'debug' => $debug, + 'enforce_global_unique' => $enforce_global_unique, + 'exempt_view_permissions' => $exempt_view_permissions, + 'login_required' => $login_required, + 'metrics_enabled' => $metrics_enabled, + 'prefer_ipv4' => $prefer_ipv4, + 'napalm_username' => $napalm_username, + 'napalm_password' => $napalm_password, + 'napalm_timeout' => $napalm_timeout, + 'time_zone' => $time_zone, + 'date_format' => $date_format, + 'short_date_format' => $short_date_format, + 'time_format' => $time_format, + 'short_time_format' => $short_time_format, + 'datetime_format' => $datetime_format, + 'short_datetime_format' => $short_datetime_format, + 'remote_auth_enabled' => $remote_auth_enabled, + 'remote_auth_backend' => $remote_auth_backend, + 'remote_auth_header' => $remote_auth_header, + 'remote_auth_first_name' => $remote_auth_first_name, + 'remote_auth_last_name' => $remote_auth_last_name, + 'remote_auth_user_email' => $remote_auth_user_email, }), owner => $user, group => $group, From 2e353fcda2cf2b117451d185422d7fb56cc84df7 Mon Sep 17 00:00:00 2001 From: Omar Morales Date: Wed, 11 Jun 2025 16:26:07 -0700 Subject: [PATCH 04/26] add remote_auth_enabled declaration --- templates/configuration.py.epp | 1 + 1 file changed, 1 insertion(+) diff --git a/templates/configuration.py.epp b/templates/configuration.py.epp index eebce4d..c710b5a 100644 --- a/templates/configuration.py.epp +++ b/templates/configuration.py.epp @@ -31,6 +31,7 @@ String $short_time_format, String $datetime_format, String $short_datetime_format, + Boolean $remote_auth_enabled, String $remote_auth_backend, String $remote_auth_header, String $remote_auth_first_name, From c0a003fcb4dc84e662abd2a68c83c8fc5ea49534 Mon Sep 17 00:00:00 2001 From: Omar Morales Date: Mon, 16 Jun 2025 12:42:08 -0700 Subject: [PATCH 05/26] metadata.json: add ubuntu --- metadata.json | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/metadata.json b/metadata.json index ef39965..1677376 100644 --- a/metadata.json +++ b/metadata.json @@ -25,6 +25,14 @@ "operatingsystemrelease": [ "8" ] + }, + { + "operatingsystem": "Ubuntu", + "operatingsystemrelease": [ + "18.04", + "20.04", + "22.04" + ] } ], "requirements": [ From 9bf121178c8e829d312578272fdd83f987e28d94 Mon Sep 17 00:00:00 2001 From: Omar Morales Date: Wed, 18 Jun 2025 17:39:15 -0700 Subject: [PATCH 06/26] install.pp add debian/ubuntu support --- manifests/install.pp | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/manifests/install.pp b/manifests/install.pp index 5ed143e..a2b00fe 100644 --- a/manifests/install.pp +++ b/manifests/install.pp @@ -79,6 +79,40 @@ Enum['tarball', 'git_clone'] $install_method = 'tarball', ) { + case $facts['os']['family'] { + 'Redhat': { + $packages = [ + gcc, + python36, + python36-devel, + libxml2-devel, + libxslt-devel, + libffi-devel, + openssl-devel, + redhat-rpm-config + ] + } + /^(Debian|Ubuntu)$/:{ + $packages = [ + python3, + python3-pip, + python3-venv, + python3-dev, + build-essential, + libxm12-dev, + libxslt1-dev, + libffi-dev, + libpq-dev, + libssl-dev, + zlib1g-dev + ] + } + default: { + fail('Unknown OS family.') + } + } + + } $packages =[ gcc, python36, From 5a8b9a35192ec37b8abdb1fa7226244e46113d21 Mon Sep 17 00:00:00 2001 From: Omar Morales Date: Wed, 2 Jul 2025 13:21:50 -0700 Subject: [PATCH 07/26] remove packages re-definition --- manifests/install.pp | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/manifests/install.pp b/manifests/install.pp index a2b00fe..28a9b91 100644 --- a/manifests/install.pp +++ b/manifests/install.pp @@ -113,16 +113,6 @@ } } - $packages =[ - gcc, - python36, - python36-devel, - libxml2-devel, - libxslt-devel, - libffi-devel, - openssl-devel, - redhat-rpm-config - ] $local_tarball = "${download_tmp_dir}/netbox-${version}.tar.gz" $software_directory_with_version = "${install_root}/netbox-${version}" From ccb88c0a886b5130a330bf4e3763397e87e8062b Mon Sep 17 00:00:00 2001 From: Omar Morales Date: Wed, 2 Jul 2025 13:22:39 -0700 Subject: [PATCH 08/26] metadata.json: remove EOL Ubuntu versions --- metadata.json | 2 -- 1 file changed, 2 deletions(-) diff --git a/metadata.json b/metadata.json index 1677376..d21ddcc 100644 --- a/metadata.json +++ b/metadata.json @@ -29,8 +29,6 @@ { "operatingsystem": "Ubuntu", "operatingsystemrelease": [ - "18.04", - "20.04", "22.04" ] } From aefeb50039956e846cf6df7756f8fe414c14bb03 Mon Sep 17 00:00:00 2001 From: Omar Morales Date: Mon, 7 Jul 2025 14:26:56 -0700 Subject: [PATCH 09/26] database.pp: change deprecated method postgresql_password --- manifests/database.pp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/manifests/database.pp b/manifests/database.pp index 4725b51..6679883 100644 --- a/manifests/database.pp +++ b/manifests/database.pp @@ -37,7 +37,7 @@ postgresql::server::db { $database_name: user => $database_user, - password => postgresql_password($database_name, $database_password), + password => postgresql::postgresql_password($database_name, $database_password), } postgresql::server::database_grant { 'user_ALL_on_database': From efb4745b72a8b46890ed91916c456e684b7ac0d0 Mon Sep 17 00:00:00 2001 From: Omar Morales Date: Tue, 8 Jul 2025 15:10:57 -0700 Subject: [PATCH 10/26] install.pp: indentation fix --- manifests/install.pp | 2 -- 1 file changed, 2 deletions(-) diff --git a/manifests/install.pp b/manifests/install.pp index 28a9b91..ddfa9fc 100644 --- a/manifests/install.pp +++ b/manifests/install.pp @@ -112,8 +112,6 @@ } } - } - $local_tarball = "${download_tmp_dir}/netbox-${version}.tar.gz" $software_directory_with_version = "${install_root}/netbox-${version}" $software_directory = "${install_root}/netbox" From ee96de766143b87c680e3c0b6259b28e7bed957c Mon Sep 17 00:00:00 2001 From: Omar Morales Date: Tue, 22 Jul 2025 14:33:38 -0700 Subject: [PATCH 11/26] init: add new config.pp variable declarations --- manifests/init.pp | 83 ++++++++++++++++++++++++++++------------------- 1 file changed, 49 insertions(+), 34 deletions(-) diff --git a/manifests/init.pp b/manifests/init.pp index 633c5c7..2efdc77 100644 --- a/manifests/init.pp +++ b/manifests/init.pp @@ -277,6 +277,14 @@ String $short_time_format = 'H:i:s', String $datetime_format = 'N j, Y g:i a', String $short_datetime_format = 'Y-m-d H:i', + Boolean $allow_api_token_retrieval = false, + Boolean $remote_auth_enabled = false, + String $remote_auth_backend = '', + String $remote_auth_header = '', + String $remote_auth_first_name = '', + String $remote_auth_last_name = '', + String $remote_auth_user_email = '', + ) { Class['netbox::install'] -> Class['netbox::config'] ~> Class['netbox::service'] @@ -347,40 +355,47 @@ } class { 'netbox::config': - user => $user, - group => $group, - install_root => $install_root, - allowed_hosts => $allowed_hosts, - database_name => $database_name, - database_user => $database_user, - database_password => $database_password, - database_host => $database_host, - database_port => $database_port, - database_conn_max_age => $database_conn_max_age, - redis_options => $redis_options, - email_options => $email_options, - secret_key => $secret_key, - admins => $admins, - banner_top => $banner_top, - banner_bottom => $banner_bottom, - banner_login => $banner_login, - base_path => $base_path, - debug => $debug, - enforce_global_unique => $enforce_global_unique, - login_required => $login_required, - metrics_enabled => $metrics_enabled, - prefer_ipv4 => $prefer_ipv4, - exempt_view_permissions => $exempt_view_permissions, - napalm_username => $napalm_username, - napalm_password => $napalm_password, - napalm_timeout => $napalm_timeout, - time_zone => $time_zone, - date_format => $date_format, - short_date_format => $short_date_format, - time_format => $time_format, - short_time_format => $short_time_format, - datetime_format => $datetime_format, - short_datetime_format => $short_datetime_format, + user => $user, + group => $group, + install_root => $install_root, + allowed_hosts => $allowed_hosts, + database_name => $database_name, + database_user => $database_user, + database_password => $database_password, + database_host => $database_host, + database_port => $database_port, + database_conn_max_age => $database_conn_max_age, + redis_options => $redis_options, + email_options => $email_options, + secret_key => $secret_key, + admins => $admins, + banner_top => $banner_top, + banner_bottom => $banner_bottom, + banner_login => $banner_login, + base_path => $base_path, + debug => $debug, + enforce_global_unique => $enforce_global_unique, + login_required => $login_required, + metrics_enabled => $metrics_enabled, + prefer_ipv4 => $prefer_ipv4, + exempt_view_permissions => $exempt_view_permissions, + napalm_username => $napalm_username, + napalm_password => $napalm_password, + napalm_timeout => $napalm_timeout, + time_zone => $time_zone, + date_format => $date_format, + short_date_format => $short_date_format, + time_format => $time_format, + short_time_format => $short_time_format, + datetime_format => $datetime_format, + short_datetime_format => $short_datetime_format, + allow_api_token_retrieval => $allow_api_token_retrieval, + remote_auth_enabled => $remote_auth_enabled, + remote_auth_backend => $remote_auth_backend, + remote_auth_header => $remote_auth_header, + remote_auth_first_name => $remote_auth_first_name, + remote_auth_last_name => $remote_auth_last_name, + remote_auth_user_email => $remote_auth_user_email, } class {'netbox::service': From f0b6d39510d4909a653043a2e8e4ef888add1572 Mon Sep 17 00:00:00 2001 From: Omar Morales Date: Thu, 24 Jul 2025 12:02:08 -0700 Subject: [PATCH 12/26] database.pp: remove dependency cycle --- manifests/database.pp | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/manifests/database.pp b/manifests/database.pp index 6679883..a20089c 100644 --- a/manifests/database.pp +++ b/manifests/database.pp @@ -28,16 +28,12 @@ String $database_locale, ){ - class { 'postgresql::globals': - encoding => $database_encoding, - locale => $database_locale, - } - ->class { 'postgresql::server': - } - +include postgresql::server postgresql::server::db { $database_name: user => $database_user, password => postgresql::postgresql_password($database_name, $database_password), + encoding => $database_encoding, + locale => $database_locale, } postgresql::server::database_grant { 'user_ALL_on_database': From 721062d82fdf59892d4729b6e7fd78847bca5203 Mon Sep 17 00:00:00 2001 From: Omar Morales Date: Fri, 25 Jul 2025 16:39:03 -0700 Subject: [PATCH 13/26] ubuntu package typo fix --- manifests/install.pp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/manifests/install.pp b/manifests/install.pp index ddfa9fc..5fea7c4 100644 --- a/manifests/install.pp +++ b/manifests/install.pp @@ -99,7 +99,7 @@ python3-venv, python3-dev, build-essential, - libxm12-dev, + libxml2-dev, libxslt1-dev, libffi-dev, libpq-dev, From 0738f0536a96a632e0c06fe5c9ddf65c5252b040 Mon Sep 17 00:00:00 2001 From: Omar Morales Date: Mon, 28 Jul 2025 14:04:01 -0700 Subject: [PATCH 14/26] install.pp: add ubuntu support for ldap packages --- manifests/install.pp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/manifests/install.pp b/manifests/install.pp index 5fea7c4..e5d3634 100644 --- a/manifests/install.pp +++ b/manifests/install.pp @@ -91,6 +91,9 @@ openssl-devel, redhat-rpm-config ] + $ldap_packages = [ + openldap-devel + ] } /^(Debian|Ubuntu)$/:{ $packages = [ @@ -106,6 +109,11 @@ libssl-dev, zlib1g-dev ] + $ldap_packages = [ + libldap2-dev, + libsasl2-dev, + libssl-dev + ] } default: { fail('Unknown OS family.') @@ -117,8 +125,6 @@ $software_directory = "${install_root}/netbox" $venv_dir = "${software_directory}/venv" - $ldap_packages = [openldap-devel] - ensure_packages($packages) if $include_ldap { From 7d4ce4700d677ce2762ec86928d197e255c93613 Mon Sep 17 00:00:00 2001 From: Omar Morales Date: Tue, 29 Jul 2025 11:37:29 -0700 Subject: [PATCH 15/26] init.pp: update version, add email variables --- manifests/init.pp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/manifests/init.pp b/manifests/init.pp index 2efdc77..e3f8946 100644 --- a/manifests/init.pp +++ b/manifests/init.pp @@ -226,9 +226,9 @@ # class netbox ( String $secret_key, - String $version = '2.10.1', - String $download_url = 'https://github.com/netbox-community/netbox/archive/v2.10.1.tar.gz', - String $download_checksum = 'b827c520e4c82842e426a5f9ad2d914d1728a3671e304d5f25eb06392c24866c', + String $version = '4.3.4', + String $download_url = 'https://github.com/netbox-community/netbox/archive/v4.3.4.tar.gz', + String $download_checksum = 'c96c6708ecdba84f1b8952151dd5760ae4ddc51c7770ea9734218b21038a230c', Stdlib::Absolutepath $download_tmp_dir = '/var/tmp', String $user = 'netbox', String $group = 'netbox', @@ -270,6 +270,8 @@ String $email_username = '', String $email_password = '', String $email_from_email = '', + Boolean $email_ssl = false, + Boolean $email_tls = false, String $time_zone = 'UTC', String $date_format = 'N j, Y', String $short_date_format = 'Y-m-d', @@ -352,6 +354,8 @@ password => $email_password, timeout => $email_timeout, from_email => $email_from_email, + ssl => $email_ssl, + tls => $email_tls, } class { 'netbox::config': From 09de375ef8622aadba6cb8334e1f7546aca0b53d Mon Sep 17 00:00:00 2001 From: Omar Morales Date: Tue, 5 Aug 2025 14:31:17 -0700 Subject: [PATCH 16/26] configuration.py.epp: update boolean values to Python booleans --- templates/configuration.py.epp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/templates/configuration.py.epp b/templates/configuration.py.epp index c710b5a..2babfe5 100644 --- a/templates/configuration.py.epp +++ b/templates/configuration.py.epp @@ -114,7 +114,7 @@ ADMINS = [ ] # Permit the retrieval of API tokens after their creation. -ALLOW_TOKEN_RETRIEVAL = <%=$allow_api_token_retrieval%> +ALLOW_TOKEN_RETRIEVAL = <%=if $allow_api_token_retrieval {'True'} else {'False'} %> # Enable any desired validators for local account passwords below. For a list of included validators, please see the # Django documentation at https://docs.djangoproject.com/en/stable/topics/auth/passwords/#password-validation. @@ -178,8 +178,8 @@ EMAIL = { 'PORT': <%=$email_options['port']%>, 'USERNAME': '<%=$email_options['username']%>', 'PASSWORD': '<%=$email_options['password']%>', - 'USE_SSL': <%=$email_options['ssl']%>, - 'USE_TLS': <%=$email_options['tls']%>, + 'USE_SSL': <%= if $email_options['ssl'] {'True'} else {'False'} %>, + 'USE_TLS': <%=if $email_options['tls'] {'True'} else {'False'} %>, 'TIMEOUT': <%=$email_options['timeout']%>, # seconds 'FROM_EMAIL': '<%=$email_options['from_email']%>', } @@ -292,7 +292,7 @@ PREFER_IPV4 = False <% } -%> # Remote authentication support -REMOTE_AUTH_ENABLED = <%=$remote_auth_enabled%> +REMOTE_AUTH_ENABLED = <%=if $remote_auth_enabled {'True'} else {'False'} %> REMOTE_AUTH_BACKEND = '<%=$remote_auth_backend%>' REMOTE_AUTH_HEADER = '<%=$remote_auth_header%>' REMOTE_AUTH_USER_FIRST_NAME = '<%=$remote_auth_first_name%>' From ccf32ecdc6c30cfc09ffc408e2dd2592fff660da Mon Sep 17 00:00:00 2001 From: Omar Morales Date: Thu, 7 Aug 2025 11:33:12 -0700 Subject: [PATCH 17/26] init.pp: parameterize redis config --- manifests/init.pp | 30 ++++++++++++++++++++---------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/manifests/init.pp b/manifests/init.pp index e3f8946..0b85d16 100644 --- a/manifests/init.pp +++ b/manifests/init.pp @@ -236,6 +236,16 @@ Stdlib::Absolutepath $install_root = '/opt', Boolean $handle_database = true, Boolean $handle_redis = true, + String $redis_host = 'localhost', + Integer $redis_port = 6379, + String $redis_password = '', + Integer $redis_database = 0, + String $redis_ssl = 'False', + String $redis_cache_host = 'localhost', + Integer $redis_cache_port = 6379, + String $redis_cache_password = '', + Integer $redis_cache_database = 1, + String $redis_cache_ssl = 'False', Boolean $install_dependencies_from_filesystem = false, Stdlib::Absolutepath $python_dependency_path = '/srv/python_dependencies', Boolean $include_napalm = true, @@ -330,20 +340,20 @@ $redis_options = { 'tasks' => { - host => 'localhost', - port => 6379, - password => '', - database => 0, + host => $redis_host, + port => $redis_port, + password => $redis_password, + database => $redis_database, default_timeout => 300, - ssl => 'False', + ssl => $redis_ssl, }, 'caching' => { - host => 'localhost', - port => 6379, - password => '', - database => 1, + host => $redis_cache_host, + port => $redis_cache_port, + password => $redis_cache_password, + database => $redis_cache_database, default_timeout => 300, - ssl => 'False', + ssl => $redis_cache_ssl, }, } From a5dce46324bdb69c72706f7222048f5d93ff550a Mon Sep 17 00:00:00 2001 From: Omar Morales Date: Fri, 8 Aug 2025 13:16:01 -0700 Subject: [PATCH 18/26] add ldap configuration support --- manifests/config.pp | 29 +++++++++++++++++++++++++++++ manifests/init.pp | 14 ++++++++++++++ templates/ldap_config.py.epp | 12 ++++++------ 3 files changed, 49 insertions(+), 6 deletions(-) diff --git a/manifests/config.pp b/manifests/config.pp index 8722fca..8939170 100644 --- a/manifests/config.pp +++ b/manifests/config.pp @@ -209,6 +209,13 @@ String $remote_auth_first_name, String $remote_auth_last_name, String $remote_auth_user_email, + String $ldap_sever_uri, + String $ad_ou, + String $ad_bind_dn, + String $ad_require_dn, + String $ldap_bind_password, + Boolean $ldap_ignore_cert_errors, + Boolean $ldap_mirror_groups, ) { $should_create_superuser = false; $software_directory = "${install_root}/netbox" @@ -281,6 +288,28 @@ notify => Exec['collect static files'], } + if $remote_auth_enabled { + + $ldap_config_file = "${software_directory}/netbox/netbox/ldap_config.py" + + file { $ldap_config_file: + content => epp('netbox/ldap_config.py.epp', { + 'ldap_sever_uri' => $ldap_sever_uri, + 'ad_ou' => $ad_ou, + 'ad_bind_dn' => $ad_bind_dn, + 'ad_require_dn' => $ad_require_dn, + 'ldap_bind_password' => $ldap_bind_password, + 'ldap_ignore_cert_errors' => $ldap_ignore_cert_errors, + 'ldap_mirror_groups' => $ldap_mirror_groups, + }), + owner => $user, + group => $group, + mode => '0644', + validate_cmd => "${venv_dir}/bin/python -m py_compile %", + notify => Exec['collect static files'], + } + } + Exec { cwd => $software_directory, path => [ "${venv_dir}/bin", '/usr/bin', '/usr/sbin' ], diff --git a/manifests/init.pp b/manifests/init.pp index 0b85d16..6ca65f7 100644 --- a/manifests/init.pp +++ b/manifests/init.pp @@ -296,6 +296,13 @@ String $remote_auth_first_name = '', String $remote_auth_last_name = '', String $remote_auth_user_email = '', + String $ldap_sever_uri = '', + String $ad_ou = '', + String $ad_bind_dn = '', + String $ad_require_dn = '', + String $ldap_bind_password = '', + Boolean $ldap_ignore_cert_errors = false, + Boolean $ldap_mirror_groups = true, ) { @@ -410,6 +417,13 @@ remote_auth_first_name => $remote_auth_first_name, remote_auth_last_name => $remote_auth_last_name, remote_auth_user_email => $remote_auth_user_email, + ldap_sever_uri => $ldap_sever_uri, + ad_ou => $ad_ou, + ad_bind_dn => $ad_bind_dn, + ad_require_dn => $ad_require_dn, + ldap_bind_password => $ldap_bind_password, + ldap_ignore_cert_errors => $ldap_ignore_cert_errors, + ldap_mirror_groups => $ldap_mirror_groups, } class {'netbox::service': diff --git a/templates/ldap_config.py.epp b/templates/ldap_config.py.epp index 943c8d3..7f58dfd 100644 --- a/templates/ldap_config.py.epp +++ b/templates/ldap_config.py.epp @@ -1,8 +1,8 @@ <% | String $ldap_sever_uri, String $ad_ou, - String $ad_bind_cn, - String $ad_require_cn, + String $ad_bind_dn, + String $ad_require_dn, String $ldap_bind_password, Boolean $ldap_ignore_cert_errors, Boolean $ldap_mirror_groups, @@ -19,13 +19,13 @@ AUTH_LDAP_CONNECTION_OPTIONS = { } # Set the DN and password for the NetBox service account. -AUTH_LDAP_BIND_DN = "<%=$ad_bind_cn%>,OU=Service Accounts,<%=$ad_ou%>" +AUTH_LDAP_BIND_DN = "<%=$ad_bind_dn%>,OU=Service Accounts,<%=$ad_ou%>" AUTH_LDAP_BIND_PASSWORD = "<%=$ldap_bind_password%>" # Include this setting if you want to ignore certificate errors. This might be needed to accept a self-signed cert. # Note that this is a NetBox-specific setting which sets: # ldap.set_option(ldap.OPT_X_TLS_REQUIRE_CERT, ldap.OPT_X_TLS_NEVER) -LDAP_IGNORE_CERT_ERRORS = <%=$ldap_ignore_cert_errors%> +LDAP_IGNORE_CERT_ERRORS = <%=if $ldap_ignore_cert_errors {'True'} else {'False'}%> # This search matches users with the sAMAccountName equal to the provided username. This is required if the user's # username is not in their DN (Active Directory). @@ -50,10 +50,10 @@ AUTH_LDAP_GROUP_SEARCH = LDAPSearch("<%=$ad_ou%>", ldap.SCOPE_SUBTREE, AUTH_LDAP_GROUP_TYPE = GroupOfNamesType() # Define a group required to login. -AUTH_LDAP_REQUIRE_GROUP = "<%=$ad_require_cn%>,<%=$ad_ou%>" +AUTH_LDAP_REQUIRE_GROUP = "<%=$ad_require_dn%>,<%=$ad_ou%>" # Mirror LDAP group assignments. -AUTH_LDAP_MIRROR_GROUPS = <%=$ldap_mirror_groups%> +AUTH_LDAP_MIRROR_GROUPS = <%=if $ldap_mirror_groups {'True'} else {'False'}%> # Define special user types using groups. Exercise great caution when assigning superuser status. AUTH_LDAP_USER_FLAGS_BY_GROUP = { From e86eb57add353b902bea2833edf72b02aafa24e0 Mon Sep 17 00:00:00 2001 From: Omar Morales Date: Mon, 8 Sep 2025 10:47:26 -0700 Subject: [PATCH 19/26] add more LDAP configurations and paramaters --- manifests/config.pp | 4 ++++ manifests/init.pp | 4 ++++ templates/ldap_config.py.epp | 24 ++++++++++++++++-------- 3 files changed, 24 insertions(+), 8 deletions(-) diff --git a/manifests/config.pp b/manifests/config.pp index 8939170..338b737 100644 --- a/manifests/config.pp +++ b/manifests/config.pp @@ -213,6 +213,8 @@ String $ad_ou, String $ad_bind_dn, String $ad_require_dn, + String $ad_admin_dn, + String $ad_superuser_dn, String $ldap_bind_password, Boolean $ldap_ignore_cert_errors, Boolean $ldap_mirror_groups, @@ -298,6 +300,8 @@ 'ad_ou' => $ad_ou, 'ad_bind_dn' => $ad_bind_dn, 'ad_require_dn' => $ad_require_dn, + 'ad_admin_dn' => $ad_admin_dn, + 'ad_superuser_dn' => $ad_superuser_dn, 'ldap_bind_password' => $ldap_bind_password, 'ldap_ignore_cert_errors' => $ldap_ignore_cert_errors, 'ldap_mirror_groups' => $ldap_mirror_groups, diff --git a/manifests/init.pp b/manifests/init.pp index 6ca65f7..a8e4ff9 100644 --- a/manifests/init.pp +++ b/manifests/init.pp @@ -300,6 +300,8 @@ String $ad_ou = '', String $ad_bind_dn = '', String $ad_require_dn = '', + String $ad_admin_dn = '', + String $ad_superuser_dn = '', String $ldap_bind_password = '', Boolean $ldap_ignore_cert_errors = false, Boolean $ldap_mirror_groups = true, @@ -421,6 +423,8 @@ ad_ou => $ad_ou, ad_bind_dn => $ad_bind_dn, ad_require_dn => $ad_require_dn, + ad_admin_dn => $ad_admin_dn, + ad_superuser_dn => $ad_superuser_dn, ldap_bind_password => $ldap_bind_password, ldap_ignore_cert_errors => $ldap_ignore_cert_errors, ldap_mirror_groups => $ldap_mirror_groups, diff --git a/templates/ldap_config.py.epp b/templates/ldap_config.py.epp index 7f58dfd..55edf40 100644 --- a/templates/ldap_config.py.epp +++ b/templates/ldap_config.py.epp @@ -3,12 +3,14 @@ String $ad_ou, String $ad_bind_dn, String $ad_require_dn, + String $ad_admin_dn, + String $ad_superuser_dn, String $ldap_bind_password, Boolean $ldap_ignore_cert_errors, Boolean $ldap_mirror_groups, | -%> import ldap -from django_auth_ldap.config import LDAPSearch, GroupOfNamesType +from django_auth_ldap.config import LDAPSearch, GroupOfNamesType, NestedActiveDirectoryGroupType # Server URI AUTH_LDAP_SERVER_URI = '<%=$ldap_sever_uri%>' @@ -19,7 +21,7 @@ AUTH_LDAP_CONNECTION_OPTIONS = { } # Set the DN and password for the NetBox service account. -AUTH_LDAP_BIND_DN = "<%=$ad_bind_dn%>,OU=Service Accounts,<%=$ad_ou%>" +AUTH_LDAP_BIND_DN = "<%=$ad_bind_dn%>,<%=$ad_ou%>" AUTH_LDAP_BIND_PASSWORD = "<%=$ldap_bind_password%>" # Include this setting if you want to ignore certificate errors. This might be needed to accept a self-signed cert. @@ -31,23 +33,29 @@ LDAP_IGNORE_CERT_ERRORS = <%=if $ldap_ignore_cert_errors {'True'} else {'False'} # username is not in their DN (Active Directory). AUTH_LDAP_USER_SEARCH = LDAPSearch("<%=$ad_ou%>", ldap.SCOPE_SUBTREE, - "(sAMAccountName=%(user)s)") + "(|(userPrincipalName=%(user)s)(sAMAccountName=%(user)s))") +AUTH_LDAP_USER_SEARCH_BASEDN = "<%=$ad_ou%>" +AUTH_LDAP_USER_SEARCH_ATTR = "sAMAccountName" +AUTH_LDAP_USER_SEARCH_FILTER = "(|(userPrincipalName=%(user)s)(sAMAccountName=%(user)s))" # If a user's DN is producible from their username, we don't need to search. -AUTH_LDAP_USER_DN_TEMPLATE = "uid=%(user)s,ou=users,<%=$ad_ou%>" +AUTH_LDAP_USER_DN_TEMPLATE = None # You can map user attributes to Django attributes as so. AUTH_LDAP_USER_ATTR_MAP = { + "username": "sAMAccountName", "first_name": "givenName", "last_name": "sn", "email": "mail" } +AUTH_LDAP_USER_QUERY_FIELD = "username" + # This search ought to return all groups to which the user belongs. django_auth_ldap uses this to determine group # hierarchy. AUTH_LDAP_GROUP_SEARCH = LDAPSearch("<%=$ad_ou%>", ldap.SCOPE_SUBTREE, "(objectClass=group)") -AUTH_LDAP_GROUP_TYPE = GroupOfNamesType() +AUTH_LDAP_GROUP_TYPE = NestedActiveDirectoryGroupType() # Define a group required to login. AUTH_LDAP_REQUIRE_GROUP = "<%=$ad_require_dn%>,<%=$ad_ou%>" @@ -57,9 +65,9 @@ AUTH_LDAP_MIRROR_GROUPS = <%=if $ldap_mirror_groups {'True'} else {'False'}%> # Define special user types using groups. Exercise great caution when assigning superuser status. AUTH_LDAP_USER_FLAGS_BY_GROUP = { - "is_active": "cn=active,ou=groups,<%=$ad_ou%>", - "is_staff": "cn=staff,ou=groups,<%=$ad_ou%>", - "is_superuser": "cn=superuser,ou=groups,<%=$ad_ou%>" + "is_active": "<%=$ad_require_dn%>,<%=$ad_ou%>", + "is_staff": "<%=$ad_admin_dn%>,<%=$ad_ou%>", + "is_superuser": "<%=$ad_superuser_dn%>,<%=$ad_ou%>" } # For more granular permissions, we can map LDAP groups to Django groups. From fd0bca93822ee1ae9e5e8cc4f3ca82fe8f75b74c Mon Sep 17 00:00:00 2001 From: Omar Morales Date: Fri, 12 Sep 2025 14:00:27 -0700 Subject: [PATCH 20/26] use puppet-python for optional python managment --- manifests/init.pp | 16 ++++++++- manifests/install.pp | 85 ++++++++++++++++++++++++-------------------- 2 files changed, 61 insertions(+), 40 deletions(-) diff --git a/manifests/init.pp b/manifests/init.pp index a8e4ff9..4efc21f 100644 --- a/manifests/init.pp +++ b/manifests/init.pp @@ -236,6 +236,7 @@ Stdlib::Absolutepath $install_root = '/opt', Boolean $handle_database = true, Boolean $handle_redis = true, + Boolean $handle_python = true, String $redis_host = 'localhost', Integer $redis_port = 6379, String $redis_password = '', @@ -305,11 +306,21 @@ String $ldap_bind_password = '', Boolean $ldap_ignore_cert_errors = false, Boolean $ldap_mirror_groups = true, - + String $python_index_url = 'https://pypi.org/simple', + String $python_cert_path = '/etc/ssl/certs/ca-certificates.crt', ) { Class['netbox::install'] -> Class['netbox::config'] ~> Class['netbox::service'] + if $handle_python { + class { 'python': + version => 'system', + pip => 'present', + dev => 'present', + venv => 'present', + } + } + if $handle_database { class { 'netbox::database': database_name => $database_name, @@ -345,6 +356,9 @@ include_ldap => $include_ldap, install_dependencies_from_filesystem => $install_dependencies_from_filesystem, python_dependency_path => $python_dependency_path, + python_index_url => $python_index_url, + python_cert_path => $python_cert_path, + } $redis_options = { diff --git a/manifests/install.pp b/manifests/install.pp index e5d3634..4b3b1f4 100644 --- a/manifests/install.pp +++ b/manifests/install.pp @@ -68,6 +68,8 @@ String $download_url, String $download_checksum, String $download_checksum_type, + String $python_index_url, + String $python_cert_path, Stdlib::Absolutepath $download_tmp_dir, String $user, String $group, @@ -83,8 +85,6 @@ 'Redhat': { $packages = [ gcc, - python36, - python36-devel, libxml2-devel, libxslt-devel, libffi-devel, @@ -97,10 +97,6 @@ } /^(Debian|Ubuntu)$/:{ $packages = [ - python3, - python3-pip, - python3-venv, - python3-dev, build-essential, libxml2-dev, libxslt1-dev, @@ -141,14 +137,6 @@ system => true, } - if $install_dependencies_from_filesystem { - $install_requirements_command = "${venv_dir}/bin/pip3 install -r requirements.txt --no-index --find-links ${python_dependency_path}" - $install_local_requirements_command = "${venv_dir}/bin/pip3 install -r local_requirements.txt --no-index --find-links ${python_dependency_path}" - } else { - $install_requirements_command = "${venv_dir}/bin/pip3 install -r requirements.txt" - $install_local_requirements_command = "${venv_dir}/bin/pip3 install -r local_requirements.txt" - } - archive { $local_tarball: source => $download_url, checksum => $download_checksum, @@ -205,31 +193,50 @@ } } - exec { "python_venv_${venv_dir}": - command => "/usr/bin/python3 -m venv ${venv_dir}", - user => $user, - creates => "${venv_dir}/bin/activate", - cwd => '/tmp', - unless => "/usr/bin/grep '^[\\t ]*VIRTUAL_ENV=[\\\\'\\\"]*${venv_dir}[\\\"\\\\'][\\t ]*$' ${venv_dir}/bin/activate", + python::dotfile { '/etc/pip.conf': + ensure => present, + owner => $user, + group => $group, + config => { + 'global' => { + 'index-url' => $python_index_url + 'cert' => $python_cert_path + } + } } - ~>exec { 'install python requirements': - cwd => $software_directory, - path => [ "${venv_dir}/bin", '/usr/bin', '/usr/sbin' ], - environment => ["VIRTUAL_ENV=${venv_dir}"], - provider => shell, - user => $user, - command => $install_requirements_command, - onlyif => "/usr/bin/grep '^[\\t ]*VIRTUAL_ENV=[\\\\'\\\"]*${venv_dir}[\\\"\\\\'][\\t ]*$' ${venv_dir}/bin/activate", - refreshonly => true, + + python::pyvenv { 'netbox_venv': + ensure => present, + owner => $user, + group => $group, + systempkgs => false, + venv_dir => "${install_root}/netbox", } - ~>exec { 'install local python requirements': - cwd => $software_directory, - path => [ "${venv_dir}/bin", '/usr/bin', '/usr/sbin' ], - environment => ["VIRTUAL_ENV=${venv_dir}"], - provider => shell, - user => $user, - command => $install_local_requirements_command, - onlyif => "/usr/bin/grep '^[\\t ]*VIRTUAL_ENV=[\\\\'\\\"]*${venv_dir}[\\\"\\\\'][\\t ]*$' ${venv_dir}/bin/activate", - refreshonly => true, + +if $install_dependencies_from_filesystem { + python::requirements { "${install_root}/netbox/requirements.txt" : + virtualenv => 'netbox_venv', + owner => $user, + group => $group, + extra_pip_args => ['--no-index','--find-links', $python_dependency_path], + } + + python::requirements { "${install_root}/netbox/local_requirements.txt" : + virtualenv => 'netbox_venv', + owner => $user, + group => $group, + extra_pip_args => ['--no-index','--find-links', $python_dependency_path], + } + } else { + python::requirements { "${install_root}/netbox/requirements.txt" : + virtualenv => 'netbox_venv', + owner => $user, + group => $group, + } + + python::requirements { "${install_root}/netbox/local_requirements.txt" : + virtualenv => 'netbox_venv', + owner => $user, + group => $group, + } } -} From cb38e0ec9a5137c1cf6105481b8c6135df85de53 Mon Sep 17 00:00:00 2001 From: Omar Morales Date: Fri, 12 Sep 2025 17:11:27 -0700 Subject: [PATCH 21/26] remove creation of pip.conf --- manifests/init.pp | 4 ---- manifests/install.pp | 15 +-------------- 2 files changed, 1 insertion(+), 18 deletions(-) diff --git a/manifests/init.pp b/manifests/init.pp index 4efc21f..1e1a63c 100644 --- a/manifests/init.pp +++ b/manifests/init.pp @@ -306,8 +306,6 @@ String $ldap_bind_password = '', Boolean $ldap_ignore_cert_errors = false, Boolean $ldap_mirror_groups = true, - String $python_index_url = 'https://pypi.org/simple', - String $python_cert_path = '/etc/ssl/certs/ca-certificates.crt', ) { Class['netbox::install'] -> Class['netbox::config'] ~> Class['netbox::service'] @@ -356,8 +354,6 @@ include_ldap => $include_ldap, install_dependencies_from_filesystem => $install_dependencies_from_filesystem, python_dependency_path => $python_dependency_path, - python_index_url => $python_index_url, - python_cert_path => $python_cert_path, } diff --git a/manifests/install.pp b/manifests/install.pp index 4b3b1f4..7e4898c 100644 --- a/manifests/install.pp +++ b/manifests/install.pp @@ -68,8 +68,6 @@ String $download_url, String $download_checksum, String $download_checksum_type, - String $python_index_url, - String $python_cert_path, Stdlib::Absolutepath $download_tmp_dir, String $user, String $group, @@ -193,18 +191,6 @@ } } - python::dotfile { '/etc/pip.conf': - ensure => present, - owner => $user, - group => $group, - config => { - 'global' => { - 'index-url' => $python_index_url - 'cert' => $python_cert_path - } - } - } - python::pyvenv { 'netbox_venv': ensure => present, owner => $user, @@ -240,3 +226,4 @@ group => $group, } } +} From 2bb37cf85994005b7de80a8b56e5bd57e5b7e7ea Mon Sep 17 00:00:00 2001 From: Omar Morales Date: Fri, 12 Sep 2025 17:11:52 -0700 Subject: [PATCH 22/26] add puppet-python to metadata.json --- metadata.json | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/metadata.json b/metadata.json index d21ddcc..2c9514a 100644 --- a/metadata.json +++ b/metadata.json @@ -11,6 +11,10 @@ { "name": "puppetlabs-stdlib", "version_requirement": ">= 1.0.0" + }, + { + "name": "puppet-python", + "version_requirement": ">= 2.0.0" } ], "operatingsystem_support": [ From 6e8a26c7428a333fdf818c75dd3feb12d21e87b5 Mon Sep 17 00:00:00 2001 From: Omar Morales Date: Thu, 25 Sep 2025 18:04:57 -0700 Subject: [PATCH 23/26] update venv dir --- manifests/install.pp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/manifests/install.pp b/manifests/install.pp index 7e4898c..8b852a6 100644 --- a/manifests/install.pp +++ b/manifests/install.pp @@ -196,7 +196,7 @@ owner => $user, group => $group, systempkgs => false, - venv_dir => "${install_root}/netbox", + venv_dir => $venv_dir, } if $install_dependencies_from_filesystem { From 4c5a2ec71c11ba0b877371d98283dfbe5b6435cc Mon Sep 17 00:00:00 2001 From: Omar Morales Date: Fri, 26 Sep 2025 10:28:52 -0700 Subject: [PATCH 24/26] update requirements virtualenv parameters --- manifests/install.pp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/manifests/install.pp b/manifests/install.pp index 8b852a6..6d8935d 100644 --- a/manifests/install.pp +++ b/manifests/install.pp @@ -201,27 +201,27 @@ if $install_dependencies_from_filesystem { python::requirements { "${install_root}/netbox/requirements.txt" : - virtualenv => 'netbox_venv', + virtualenv => $venv_dir, owner => $user, group => $group, extra_pip_args => ['--no-index','--find-links', $python_dependency_path], } python::requirements { "${install_root}/netbox/local_requirements.txt" : - virtualenv => 'netbox_venv', + virtualenv => $venv_dir, owner => $user, group => $group, extra_pip_args => ['--no-index','--find-links', $python_dependency_path], } } else { python::requirements { "${install_root}/netbox/requirements.txt" : - virtualenv => 'netbox_venv', + virtualenv => $venv_dir, owner => $user, group => $group, } python::requirements { "${install_root}/netbox/local_requirements.txt" : - virtualenv => 'netbox_venv', + virtualenv => $venv_dir, owner => $user, group => $group, } From 77944e6d6eea2bf519bbdfe730784e7845c5b408 Mon Sep 17 00:00:00 2001 From: Omar Morales Date: Fri, 26 Sep 2025 11:05:25 -0700 Subject: [PATCH 25/26] remove old references to Exec --- manifests/install.pp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/manifests/install.pp b/manifests/install.pp index 6d8935d..e9fa1e1 100644 --- a/manifests/install.pp +++ b/manifests/install.pp @@ -143,7 +143,6 @@ extract_path => $install_root, creates => $software_directory_with_version, cleanup => true, - notify => Exec['install python requirements'], } exec { 'netbox permission': @@ -168,7 +167,6 @@ file_line { 'napalm': path => "${software_directory}/local_requirements.txt", line => 'napalm', - notify => Exec['install local python requirements'], require => File['local_requirements'] } } @@ -177,7 +175,6 @@ file_line { 'django_storages': path => "${software_directory}/local_requirements.txt", line => 'django-storages', - notify => Exec['install local python requirements'], require => File['local_requirements'] } } @@ -186,7 +183,6 @@ file_line { 'ldap': path => "${software_directory}/local_requirements.txt", line => 'django-auth-ldap', - notify => Exec['install local python requirements'], require => File['local_requirements'] } } From 3c5b584ea27197914e453b1d59394a56882626bc Mon Sep 17 00:00:00 2001 From: Omar Morales Date: Fri, 26 Sep 2025 12:17:02 -0700 Subject: [PATCH 26/26] set python version to 3 --- manifests/init.pp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/manifests/init.pp b/manifests/init.pp index 1e1a63c..48d7977 100644 --- a/manifests/init.pp +++ b/manifests/init.pp @@ -312,7 +312,7 @@ if $handle_python { class { 'python': - version => 'system', + version => '3', pip => 'present', dev => 'present', venv => 'present',