diff --git a/.devcontainer/entrypoint.sh b/.devcontainer/entrypoint.sh index 05c20cace5..3308f79ea6 100644 --- a/.devcontainer/entrypoint.sh +++ b/.devcontainer/entrypoint.sh @@ -98,6 +98,7 @@ MESH_TOKEN_KEY = '${MESH_TOKEN}' REDIS_HOST = '${REDIS_HOST}' MESH_WS_URL = '${MESH_WS_URL}' ADMIN_ENABLED = True +TRMM_INSECURE = True EOF )" diff --git a/.github/workflows/ci-tests.yml b/.github/workflows/ci-tests.yml index 2b2ca20990..497f0c6d21 100644 --- a/.github/workflows/ci-tests.yml +++ b/.github/workflows/ci-tests.yml @@ -17,7 +17,7 @@ jobs: python-version: ["3.11.6"] steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - uses: harmon758/postgresql-action@v1 with: diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml deleted file mode 100644 index 31130a219c..0000000000 --- a/.github/workflows/codeql-analysis.yml +++ /dev/null @@ -1,70 +0,0 @@ -# For most projects, this workflow file will not need changing; you simply need -# to commit it to your repository. -# -# You may wish to alter this file to override the set of languages analyzed, -# or to provide custom queries or build logic. -# -# ******** NOTE ******** -# We have attempted to detect the languages in your repository. Please check -# the `language` matrix defined below to confirm you have the correct set of -# supported CodeQL languages. -# -name: "CodeQL" - -on: - push: - branches: [ develop ] - pull_request: - # The branches below must be a subset of the branches above - branches: [ develop ] - schedule: - - cron: '19 14 * * 6' - -jobs: - analyze: - name: Analyze - runs-on: ubuntu-latest - permissions: - actions: read - contents: read - security-events: write - - strategy: - fail-fast: false - matrix: - language: [ 'go', 'python' ] - # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ] - # Learn more about CodeQL language support at https://git.io/codeql-language-support - - steps: - - name: Checkout repository - uses: actions/checkout@v2 - - # Initializes the CodeQL tools for scanning. - - name: Initialize CodeQL - uses: github/codeql-action/init@v1 - with: - languages: ${{ matrix.language }} - # If you wish to specify custom queries, you can do so here or in a config file. - # By default, queries listed here will override any specified in a config file. - # Prefix the list here with "+" to use these queries and those in the config file. - # queries: ./path/to/local/query, your-org/your-repo/queries@main - - # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). - # If this step fails, then you should remove it and run the build manually (see below) - - name: Autobuild - uses: github/codeql-action/autobuild@v1 - - # ℹī¸ Command-line programs to run using the OS shell. - # 📚 https://git.io/JvXDl - - # ✏ī¸ If the Autobuild fails above, remove it and uncomment the following three lines - # and modify them (or add more) to build your code if your project - # uses a compiled language - - #- run: | - # make bootstrap - # make release - - - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v1 diff --git a/.github/workflows/docker-build-push.yml b/.github/workflows/docker-build-push.yml index 027028df8f..da93f9c20a 100644 --- a/.github/workflows/docker-build-push.yml +++ b/.github/workflows/docker-build-push.yml @@ -9,24 +9,24 @@ jobs: runs-on: ubuntu-latest steps: - name: Check out the repo - uses: actions/checkout@v2 - + uses: actions/checkout@v4 + - name: Get Github Tag id: prep run: | echo ::set-output name=version::${GITHUB_REF#refs/tags/v} - name: Set up QEMU uses: docker/setup-qemu-action@v1 - + - name: Set up Docker Buildx uses: docker/setup-buildx-action@v1 - + - name: Login to DockerHub - uses: docker/login-action@v1 + uses: docker/login-action@v1 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} - + - name: Build and Push Tactical Image uses: docker/build-push-action@v2 with: @@ -36,7 +36,7 @@ jobs: file: ./docker/containers/tactical/dockerfile platforms: linux/amd64 tags: tacticalrmm/tactical:${{ steps.prep.outputs.version }},tacticalrmm/tactical:latest - + - name: Build and Push Tactical MeshCentral Image uses: docker/build-push-action@v2 with: @@ -46,7 +46,7 @@ jobs: file: ./docker/containers/tactical-meshcentral/dockerfile platforms: linux/amd64 tags: tacticalrmm/tactical-meshcentral:${{ steps.prep.outputs.version }},tacticalrmm/tactical-meshcentral:latest - + - name: Build and Push Tactical NATS Image uses: docker/build-push-action@v2 with: @@ -56,7 +56,7 @@ jobs: file: ./docker/containers/tactical-nats/dockerfile platforms: linux/amd64 tags: tacticalrmm/tactical-nats:${{ steps.prep.outputs.version }},tacticalrmm/tactical-nats:latest - + - name: Build and Push Tactical Frontend Image uses: docker/build-push-action@v2 with: @@ -66,7 +66,7 @@ jobs: file: ./docker/containers/tactical-frontend/dockerfile platforms: linux/amd64 tags: tacticalrmm/tactical-frontend:${{ steps.prep.outputs.version }},tacticalrmm/tactical-frontend:latest - + - name: Build and Push Tactical Nginx Image uses: docker/build-push-action@v2 with: diff --git a/api/tacticalrmm/accounts/migrations/0036_remove_role_can_ping_agents.py b/api/tacticalrmm/accounts/migrations/0036_remove_role_can_ping_agents.py new file mode 100644 index 0000000000..bd525af6c5 --- /dev/null +++ b/api/tacticalrmm/accounts/migrations/0036_remove_role_can_ping_agents.py @@ -0,0 +1,16 @@ +# Generated by Django 4.2.7 on 2023-11-09 19:57 + +from django.db import migrations + + +class Migration(migrations.Migration): + dependencies = [ + ("accounts", "0035_role_can_manage_reports_role_can_view_reports"), + ] + + operations = [ + migrations.RemoveField( + model_name="role", + name="can_ping_agents", + ), + ] diff --git a/api/tacticalrmm/accounts/models.py b/api/tacticalrmm/accounts/models.py index 73d6ba403a..e8ed412392 100644 --- a/api/tacticalrmm/accounts/models.py +++ b/api/tacticalrmm/accounts/models.py @@ -95,7 +95,6 @@ class Role(BaseAuditModel): # agents can_list_agents = models.BooleanField(default=False) - can_ping_agents = models.BooleanField(default=False) can_use_mesh = models.BooleanField(default=False) can_uninstall_agents = models.BooleanField(default=False) can_update_agents = models.BooleanField(default=False) diff --git a/api/tacticalrmm/accounts/views.py b/api/tacticalrmm/accounts/views.py index 0dbe92337d..f16fc30e83 100644 --- a/api/tacticalrmm/accounts/views.py +++ b/api/tacticalrmm/accounts/views.py @@ -3,13 +3,14 @@ from django.contrib.auth import login from django.db import IntegrityError from django.shortcuts import get_object_or_404 -from ipware import get_client_ip from knox.views import LoginView as KnoxLoginView +from python_ipware import IpWare from rest_framework.authtoken.serializers import AuthTokenSerializer from rest_framework.permissions import AllowAny, IsAuthenticated from rest_framework.response import Response from rest_framework.views import APIView +from accounts.utils import is_root_user from logs.models import AuditLog from tacticalrmm.helpers import notify_error @@ -22,7 +23,6 @@ UserSerializer, UserUISerializer, ) -from accounts.utils import is_root_user class CheckCreds(KnoxLoginView): @@ -79,9 +79,11 @@ def post(self, request, format=None): login(request, user) # save ip information - client_ip, _ = get_client_ip(request) - user.last_login_ip = client_ip - user.save() + ipw = IpWare() + client_ip, _ = ipw.get_client_ip(request.META) + if client_ip: + user.last_login_ip = str(client_ip) + user.save() AuditLog.audit_user_login_successful( request.data["username"], debug_info={"ip": request._client_ip} diff --git a/api/tacticalrmm/agents/migrations/0058_alter_agent_time_zone.py b/api/tacticalrmm/agents/migrations/0058_alter_agent_time_zone.py new file mode 100644 index 0000000000..31ba36eca5 --- /dev/null +++ b/api/tacticalrmm/agents/migrations/0058_alter_agent_time_zone.py @@ -0,0 +1,633 @@ +# Generated by Django 4.2.7 on 2023-11-09 19:56 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + dependencies = [ + ("agents", "0057_alter_agentcustomfield_unique_together"), + ] + + operations = [ + migrations.AlterField( + model_name="agent", + name="time_zone", + field=models.CharField( + blank=True, + choices=[ + ("Africa/Abidjan", "Africa/Abidjan"), + ("Africa/Accra", "Africa/Accra"), + ("Africa/Addis_Ababa", "Africa/Addis_Ababa"), + ("Africa/Algiers", "Africa/Algiers"), + ("Africa/Asmara", "Africa/Asmara"), + ("Africa/Asmera", "Africa/Asmera"), + ("Africa/Bamako", "Africa/Bamako"), + ("Africa/Bangui", "Africa/Bangui"), + ("Africa/Banjul", "Africa/Banjul"), + ("Africa/Bissau", "Africa/Bissau"), + ("Africa/Blantyre", "Africa/Blantyre"), + ("Africa/Brazzaville", "Africa/Brazzaville"), + ("Africa/Bujumbura", "Africa/Bujumbura"), + ("Africa/Cairo", "Africa/Cairo"), + ("Africa/Casablanca", "Africa/Casablanca"), + ("Africa/Ceuta", "Africa/Ceuta"), + ("Africa/Conakry", "Africa/Conakry"), + ("Africa/Dakar", "Africa/Dakar"), + ("Africa/Dar_es_Salaam", "Africa/Dar_es_Salaam"), + ("Africa/Djibouti", "Africa/Djibouti"), + ("Africa/Douala", "Africa/Douala"), + ("Africa/El_Aaiun", "Africa/El_Aaiun"), + ("Africa/Freetown", "Africa/Freetown"), + ("Africa/Gaborone", "Africa/Gaborone"), + ("Africa/Harare", "Africa/Harare"), + ("Africa/Johannesburg", "Africa/Johannesburg"), + ("Africa/Juba", "Africa/Juba"), + ("Africa/Kampala", "Africa/Kampala"), + ("Africa/Khartoum", "Africa/Khartoum"), + ("Africa/Kigali", "Africa/Kigali"), + ("Africa/Kinshasa", "Africa/Kinshasa"), + ("Africa/Lagos", "Africa/Lagos"), + ("Africa/Libreville", "Africa/Libreville"), + ("Africa/Lome", "Africa/Lome"), + ("Africa/Luanda", "Africa/Luanda"), + ("Africa/Lubumbashi", "Africa/Lubumbashi"), + ("Africa/Lusaka", "Africa/Lusaka"), + ("Africa/Malabo", "Africa/Malabo"), + ("Africa/Maputo", "Africa/Maputo"), + ("Africa/Maseru", "Africa/Maseru"), + ("Africa/Mbabane", "Africa/Mbabane"), + ("Africa/Mogadishu", "Africa/Mogadishu"), + ("Africa/Monrovia", "Africa/Monrovia"), + ("Africa/Nairobi", "Africa/Nairobi"), + ("Africa/Ndjamena", "Africa/Ndjamena"), + ("Africa/Niamey", "Africa/Niamey"), + ("Africa/Nouakchott", "Africa/Nouakchott"), + ("Africa/Ouagadougou", "Africa/Ouagadougou"), + ("Africa/Porto-Novo", "Africa/Porto-Novo"), + ("Africa/Sao_Tome", "Africa/Sao_Tome"), + ("Africa/Timbuktu", "Africa/Timbuktu"), + ("Africa/Tripoli", "Africa/Tripoli"), + ("Africa/Tunis", "Africa/Tunis"), + ("Africa/Windhoek", "Africa/Windhoek"), + ("America/Adak", "America/Adak"), + ("America/Anchorage", "America/Anchorage"), + ("America/Anguilla", "America/Anguilla"), + ("America/Antigua", "America/Antigua"), + ("America/Araguaina", "America/Araguaina"), + ( + "America/Argentina/Buenos_Aires", + "America/Argentina/Buenos_Aires", + ), + ("America/Argentina/Catamarca", "America/Argentina/Catamarca"), + ( + "America/Argentina/ComodRivadavia", + "America/Argentina/ComodRivadavia", + ), + ("America/Argentina/Cordoba", "America/Argentina/Cordoba"), + ("America/Argentina/Jujuy", "America/Argentina/Jujuy"), + ("America/Argentina/La_Rioja", "America/Argentina/La_Rioja"), + ("America/Argentina/Mendoza", "America/Argentina/Mendoza"), + ( + "America/Argentina/Rio_Gallegos", + "America/Argentina/Rio_Gallegos", + ), + ("America/Argentina/Salta", "America/Argentina/Salta"), + ("America/Argentina/San_Juan", "America/Argentina/San_Juan"), + ("America/Argentina/San_Luis", "America/Argentina/San_Luis"), + ("America/Argentina/Tucuman", "America/Argentina/Tucuman"), + ("America/Argentina/Ushuaia", "America/Argentina/Ushuaia"), + ("America/Aruba", "America/Aruba"), + ("America/Asuncion", "America/Asuncion"), + ("America/Atikokan", "America/Atikokan"), + ("America/Atka", "America/Atka"), + ("America/Bahia", "America/Bahia"), + ("America/Bahia_Banderas", "America/Bahia_Banderas"), + ("America/Barbados", "America/Barbados"), + ("America/Belem", "America/Belem"), + ("America/Belize", "America/Belize"), + ("America/Blanc-Sablon", "America/Blanc-Sablon"), + ("America/Boa_Vista", "America/Boa_Vista"), + ("America/Bogota", "America/Bogota"), + ("America/Boise", "America/Boise"), + ("America/Buenos_Aires", "America/Buenos_Aires"), + ("America/Cambridge_Bay", "America/Cambridge_Bay"), + ("America/Campo_Grande", "America/Campo_Grande"), + ("America/Cancun", "America/Cancun"), + ("America/Caracas", "America/Caracas"), + ("America/Catamarca", "America/Catamarca"), + ("America/Cayenne", "America/Cayenne"), + ("America/Cayman", "America/Cayman"), + ("America/Chicago", "America/Chicago"), + ("America/Chihuahua", "America/Chihuahua"), + ("America/Ciudad_Juarez", "America/Ciudad_Juarez"), + ("America/Coral_Harbour", "America/Coral_Harbour"), + ("America/Cordoba", "America/Cordoba"), + ("America/Costa_Rica", "America/Costa_Rica"), + ("America/Creston", "America/Creston"), + ("America/Cuiaba", "America/Cuiaba"), + ("America/Curacao", "America/Curacao"), + ("America/Danmarkshavn", "America/Danmarkshavn"), + ("America/Dawson", "America/Dawson"), + ("America/Dawson_Creek", "America/Dawson_Creek"), + ("America/Denver", "America/Denver"), + ("America/Detroit", "America/Detroit"), + ("America/Dominica", "America/Dominica"), + ("America/Edmonton", "America/Edmonton"), + ("America/Eirunepe", "America/Eirunepe"), + ("America/El_Salvador", "America/El_Salvador"), + ("America/Ensenada", "America/Ensenada"), + ("America/Fort_Nelson", "America/Fort_Nelson"), + ("America/Fort_Wayne", "America/Fort_Wayne"), + ("America/Fortaleza", "America/Fortaleza"), + ("America/Glace_Bay", "America/Glace_Bay"), + ("America/Godthab", "America/Godthab"), + ("America/Goose_Bay", "America/Goose_Bay"), + ("America/Grand_Turk", "America/Grand_Turk"), + ("America/Grenada", "America/Grenada"), + ("America/Guadeloupe", "America/Guadeloupe"), + ("America/Guatemala", "America/Guatemala"), + ("America/Guayaquil", "America/Guayaquil"), + ("America/Guyana", "America/Guyana"), + ("America/Halifax", "America/Halifax"), + ("America/Havana", "America/Havana"), + ("America/Hermosillo", "America/Hermosillo"), + ("America/Indiana/Indianapolis", "America/Indiana/Indianapolis"), + ("America/Indiana/Knox", "America/Indiana/Knox"), + ("America/Indiana/Marengo", "America/Indiana/Marengo"), + ("America/Indiana/Petersburg", "America/Indiana/Petersburg"), + ("America/Indiana/Tell_City", "America/Indiana/Tell_City"), + ("America/Indiana/Vevay", "America/Indiana/Vevay"), + ("America/Indiana/Vincennes", "America/Indiana/Vincennes"), + ("America/Indiana/Winamac", "America/Indiana/Winamac"), + ("America/Indianapolis", "America/Indianapolis"), + ("America/Inuvik", "America/Inuvik"), + ("America/Iqaluit", "America/Iqaluit"), + ("America/Jamaica", "America/Jamaica"), + ("America/Jujuy", "America/Jujuy"), + ("America/Juneau", "America/Juneau"), + ("America/Kentucky/Louisville", "America/Kentucky/Louisville"), + ("America/Kentucky/Monticello", "America/Kentucky/Monticello"), + ("America/Knox_IN", "America/Knox_IN"), + ("America/Kralendijk", "America/Kralendijk"), + ("America/La_Paz", "America/La_Paz"), + ("America/Lima", "America/Lima"), + ("America/Los_Angeles", "America/Los_Angeles"), + ("America/Louisville", "America/Louisville"), + ("America/Lower_Princes", "America/Lower_Princes"), + ("America/Maceio", "America/Maceio"), + ("America/Managua", "America/Managua"), + ("America/Manaus", "America/Manaus"), + ("America/Marigot", "America/Marigot"), + ("America/Martinique", "America/Martinique"), + ("America/Matamoros", "America/Matamoros"), + ("America/Mazatlan", "America/Mazatlan"), + ("America/Mendoza", "America/Mendoza"), + ("America/Menominee", "America/Menominee"), + ("America/Merida", "America/Merida"), + ("America/Metlakatla", "America/Metlakatla"), + ("America/Mexico_City", "America/Mexico_City"), + ("America/Miquelon", "America/Miquelon"), + ("America/Moncton", "America/Moncton"), + ("America/Monterrey", "America/Monterrey"), + ("America/Montevideo", "America/Montevideo"), + ("America/Montreal", "America/Montreal"), + ("America/Montserrat", "America/Montserrat"), + ("America/Nassau", "America/Nassau"), + ("America/New_York", "America/New_York"), + ("America/Nipigon", "America/Nipigon"), + ("America/Nome", "America/Nome"), + ("America/Noronha", "America/Noronha"), + ("America/North_Dakota/Beulah", "America/North_Dakota/Beulah"), + ("America/North_Dakota/Center", "America/North_Dakota/Center"), + ( + "America/North_Dakota/New_Salem", + "America/North_Dakota/New_Salem", + ), + ("America/Nuuk", "America/Nuuk"), + ("America/Ojinaga", "America/Ojinaga"), + ("America/Panama", "America/Panama"), + ("America/Pangnirtung", "America/Pangnirtung"), + ("America/Paramaribo", "America/Paramaribo"), + ("America/Phoenix", "America/Phoenix"), + ("America/Port-au-Prince", "America/Port-au-Prince"), + ("America/Port_of_Spain", "America/Port_of_Spain"), + ("America/Porto_Acre", "America/Porto_Acre"), + ("America/Porto_Velho", "America/Porto_Velho"), + ("America/Puerto_Rico", "America/Puerto_Rico"), + ("America/Punta_Arenas", "America/Punta_Arenas"), + ("America/Rainy_River", "America/Rainy_River"), + ("America/Rankin_Inlet", "America/Rankin_Inlet"), + ("America/Recife", "America/Recife"), + ("America/Regina", "America/Regina"), + ("America/Resolute", "America/Resolute"), + ("America/Rio_Branco", "America/Rio_Branco"), + ("America/Rosario", "America/Rosario"), + ("America/Santa_Isabel", "America/Santa_Isabel"), + ("America/Santarem", "America/Santarem"), + ("America/Santiago", "America/Santiago"), + ("America/Santo_Domingo", "America/Santo_Domingo"), + ("America/Sao_Paulo", "America/Sao_Paulo"), + ("America/Scoresbysund", "America/Scoresbysund"), + ("America/Shiprock", "America/Shiprock"), + ("America/Sitka", "America/Sitka"), + ("America/St_Barthelemy", "America/St_Barthelemy"), + ("America/St_Johns", "America/St_Johns"), + ("America/St_Kitts", "America/St_Kitts"), + ("America/St_Lucia", "America/St_Lucia"), + ("America/St_Thomas", "America/St_Thomas"), + ("America/St_Vincent", "America/St_Vincent"), + ("America/Swift_Current", "America/Swift_Current"), + ("America/Tegucigalpa", "America/Tegucigalpa"), + ("America/Thule", "America/Thule"), + ("America/Thunder_Bay", "America/Thunder_Bay"), + ("America/Tijuana", "America/Tijuana"), + ("America/Toronto", "America/Toronto"), + ("America/Tortola", "America/Tortola"), + ("America/Vancouver", "America/Vancouver"), + ("America/Virgin", "America/Virgin"), + ("America/Whitehorse", "America/Whitehorse"), + ("America/Winnipeg", "America/Winnipeg"), + ("America/Yakutat", "America/Yakutat"), + ("America/Yellowknife", "America/Yellowknife"), + ("Antarctica/Casey", "Antarctica/Casey"), + ("Antarctica/Davis", "Antarctica/Davis"), + ("Antarctica/DumontDUrville", "Antarctica/DumontDUrville"), + ("Antarctica/Macquarie", "Antarctica/Macquarie"), + ("Antarctica/Mawson", "Antarctica/Mawson"), + ("Antarctica/McMurdo", "Antarctica/McMurdo"), + ("Antarctica/Palmer", "Antarctica/Palmer"), + ("Antarctica/Rothera", "Antarctica/Rothera"), + ("Antarctica/South_Pole", "Antarctica/South_Pole"), + ("Antarctica/Syowa", "Antarctica/Syowa"), + ("Antarctica/Troll", "Antarctica/Troll"), + ("Antarctica/Vostok", "Antarctica/Vostok"), + ("Arctic/Longyearbyen", "Arctic/Longyearbyen"), + ("Asia/Aden", "Asia/Aden"), + ("Asia/Almaty", "Asia/Almaty"), + ("Asia/Amman", "Asia/Amman"), + ("Asia/Anadyr", "Asia/Anadyr"), + ("Asia/Aqtau", "Asia/Aqtau"), + ("Asia/Aqtobe", "Asia/Aqtobe"), + ("Asia/Ashgabat", "Asia/Ashgabat"), + ("Asia/Ashkhabad", "Asia/Ashkhabad"), + ("Asia/Atyrau", "Asia/Atyrau"), + ("Asia/Baghdad", "Asia/Baghdad"), + ("Asia/Bahrain", "Asia/Bahrain"), + ("Asia/Baku", "Asia/Baku"), + ("Asia/Bangkok", "Asia/Bangkok"), + ("Asia/Barnaul", "Asia/Barnaul"), + ("Asia/Beirut", "Asia/Beirut"), + ("Asia/Bishkek", "Asia/Bishkek"), + ("Asia/Brunei", "Asia/Brunei"), + ("Asia/Calcutta", "Asia/Calcutta"), + ("Asia/Chita", "Asia/Chita"), + ("Asia/Choibalsan", "Asia/Choibalsan"), + ("Asia/Chongqing", "Asia/Chongqing"), + ("Asia/Chungking", "Asia/Chungking"), + ("Asia/Colombo", "Asia/Colombo"), + ("Asia/Dacca", "Asia/Dacca"), + ("Asia/Damascus", "Asia/Damascus"), + ("Asia/Dhaka", "Asia/Dhaka"), + ("Asia/Dili", "Asia/Dili"), + ("Asia/Dubai", "Asia/Dubai"), + ("Asia/Dushanbe", "Asia/Dushanbe"), + ("Asia/Famagusta", "Asia/Famagusta"), + ("Asia/Gaza", "Asia/Gaza"), + ("Asia/Harbin", "Asia/Harbin"), + ("Asia/Hebron", "Asia/Hebron"), + ("Asia/Ho_Chi_Minh", "Asia/Ho_Chi_Minh"), + ("Asia/Hong_Kong", "Asia/Hong_Kong"), + ("Asia/Hovd", "Asia/Hovd"), + ("Asia/Irkutsk", "Asia/Irkutsk"), + ("Asia/Istanbul", "Asia/Istanbul"), + ("Asia/Jakarta", "Asia/Jakarta"), + ("Asia/Jayapura", "Asia/Jayapura"), + ("Asia/Jerusalem", "Asia/Jerusalem"), + ("Asia/Kabul", "Asia/Kabul"), + ("Asia/Kamchatka", "Asia/Kamchatka"), + ("Asia/Karachi", "Asia/Karachi"), + ("Asia/Kashgar", "Asia/Kashgar"), + ("Asia/Kathmandu", "Asia/Kathmandu"), + ("Asia/Katmandu", "Asia/Katmandu"), + ("Asia/Khandyga", "Asia/Khandyga"), + ("Asia/Kolkata", "Asia/Kolkata"), + ("Asia/Krasnoyarsk", "Asia/Krasnoyarsk"), + ("Asia/Kuala_Lumpur", "Asia/Kuala_Lumpur"), + ("Asia/Kuching", "Asia/Kuching"), + ("Asia/Kuwait", "Asia/Kuwait"), + ("Asia/Macao", "Asia/Macao"), + ("Asia/Macau", "Asia/Macau"), + ("Asia/Magadan", "Asia/Magadan"), + ("Asia/Makassar", "Asia/Makassar"), + ("Asia/Manila", "Asia/Manila"), + ("Asia/Muscat", "Asia/Muscat"), + ("Asia/Nicosia", "Asia/Nicosia"), + ("Asia/Novokuznetsk", "Asia/Novokuznetsk"), + ("Asia/Novosibirsk", "Asia/Novosibirsk"), + ("Asia/Omsk", "Asia/Omsk"), + ("Asia/Oral", "Asia/Oral"), + ("Asia/Phnom_Penh", "Asia/Phnom_Penh"), + ("Asia/Pontianak", "Asia/Pontianak"), + ("Asia/Pyongyang", "Asia/Pyongyang"), + ("Asia/Qatar", "Asia/Qatar"), + ("Asia/Qostanay", "Asia/Qostanay"), + ("Asia/Qyzylorda", "Asia/Qyzylorda"), + ("Asia/Rangoon", "Asia/Rangoon"), + ("Asia/Riyadh", "Asia/Riyadh"), + ("Asia/Saigon", "Asia/Saigon"), + ("Asia/Sakhalin", "Asia/Sakhalin"), + ("Asia/Samarkand", "Asia/Samarkand"), + ("Asia/Seoul", "Asia/Seoul"), + ("Asia/Shanghai", "Asia/Shanghai"), + ("Asia/Singapore", "Asia/Singapore"), + ("Asia/Srednekolymsk", "Asia/Srednekolymsk"), + ("Asia/Taipei", "Asia/Taipei"), + ("Asia/Tashkent", "Asia/Tashkent"), + ("Asia/Tbilisi", "Asia/Tbilisi"), + ("Asia/Tehran", "Asia/Tehran"), + ("Asia/Tel_Aviv", "Asia/Tel_Aviv"), + ("Asia/Thimbu", "Asia/Thimbu"), + ("Asia/Thimphu", "Asia/Thimphu"), + ("Asia/Tokyo", "Asia/Tokyo"), + ("Asia/Tomsk", "Asia/Tomsk"), + ("Asia/Ujung_Pandang", "Asia/Ujung_Pandang"), + ("Asia/Ulaanbaatar", "Asia/Ulaanbaatar"), + ("Asia/Ulan_Bator", "Asia/Ulan_Bator"), + ("Asia/Urumqi", "Asia/Urumqi"), + ("Asia/Ust-Nera", "Asia/Ust-Nera"), + ("Asia/Vientiane", "Asia/Vientiane"), + ("Asia/Vladivostok", "Asia/Vladivostok"), + ("Asia/Yakutsk", "Asia/Yakutsk"), + ("Asia/Yangon", "Asia/Yangon"), + ("Asia/Yekaterinburg", "Asia/Yekaterinburg"), + ("Asia/Yerevan", "Asia/Yerevan"), + ("Atlantic/Azores", "Atlantic/Azores"), + ("Atlantic/Bermuda", "Atlantic/Bermuda"), + ("Atlantic/Canary", "Atlantic/Canary"), + ("Atlantic/Cape_Verde", "Atlantic/Cape_Verde"), + ("Atlantic/Faeroe", "Atlantic/Faeroe"), + ("Atlantic/Faroe", "Atlantic/Faroe"), + ("Atlantic/Jan_Mayen", "Atlantic/Jan_Mayen"), + ("Atlantic/Madeira", "Atlantic/Madeira"), + ("Atlantic/Reykjavik", "Atlantic/Reykjavik"), + ("Atlantic/South_Georgia", "Atlantic/South_Georgia"), + ("Atlantic/St_Helena", "Atlantic/St_Helena"), + ("Atlantic/Stanley", "Atlantic/Stanley"), + ("Australia/ACT", "Australia/ACT"), + ("Australia/Adelaide", "Australia/Adelaide"), + ("Australia/Brisbane", "Australia/Brisbane"), + ("Australia/Broken_Hill", "Australia/Broken_Hill"), + ("Australia/Canberra", "Australia/Canberra"), + ("Australia/Currie", "Australia/Currie"), + ("Australia/Darwin", "Australia/Darwin"), + ("Australia/Eucla", "Australia/Eucla"), + ("Australia/Hobart", "Australia/Hobart"), + ("Australia/LHI", "Australia/LHI"), + ("Australia/Lindeman", "Australia/Lindeman"), + ("Australia/Lord_Howe", "Australia/Lord_Howe"), + ("Australia/Melbourne", "Australia/Melbourne"), + ("Australia/NSW", "Australia/NSW"), + ("Australia/North", "Australia/North"), + ("Australia/Perth", "Australia/Perth"), + ("Australia/Queensland", "Australia/Queensland"), + ("Australia/South", "Australia/South"), + ("Australia/Sydney", "Australia/Sydney"), + ("Australia/Tasmania", "Australia/Tasmania"), + ("Australia/Victoria", "Australia/Victoria"), + ("Australia/West", "Australia/West"), + ("Australia/Yancowinna", "Australia/Yancowinna"), + ("Brazil/Acre", "Brazil/Acre"), + ("Brazil/DeNoronha", "Brazil/DeNoronha"), + ("Brazil/East", "Brazil/East"), + ("Brazil/West", "Brazil/West"), + ("CET", "CET"), + ("CST6CDT", "CST6CDT"), + ("Canada/Atlantic", "Canada/Atlantic"), + ("Canada/Central", "Canada/Central"), + ("Canada/Eastern", "Canada/Eastern"), + ("Canada/Mountain", "Canada/Mountain"), + ("Canada/Newfoundland", "Canada/Newfoundland"), + ("Canada/Pacific", "Canada/Pacific"), + ("Canada/Saskatchewan", "Canada/Saskatchewan"), + ("Canada/Yukon", "Canada/Yukon"), + ("Chile/Continental", "Chile/Continental"), + ("Chile/EasterIsland", "Chile/EasterIsland"), + ("Cuba", "Cuba"), + ("EET", "EET"), + ("EST", "EST"), + ("EST5EDT", "EST5EDT"), + ("Egypt", "Egypt"), + ("Eire", "Eire"), + ("Etc/GMT", "Etc/GMT"), + ("Etc/GMT+0", "Etc/GMT+0"), + ("Etc/GMT+1", "Etc/GMT+1"), + ("Etc/GMT+10", "Etc/GMT+10"), + ("Etc/GMT+11", "Etc/GMT+11"), + ("Etc/GMT+12", "Etc/GMT+12"), + ("Etc/GMT+2", "Etc/GMT+2"), + ("Etc/GMT+3", "Etc/GMT+3"), + ("Etc/GMT+4", "Etc/GMT+4"), + ("Etc/GMT+5", "Etc/GMT+5"), + ("Etc/GMT+6", "Etc/GMT+6"), + ("Etc/GMT+7", "Etc/GMT+7"), + ("Etc/GMT+8", "Etc/GMT+8"), + ("Etc/GMT+9", "Etc/GMT+9"), + ("Etc/GMT-0", "Etc/GMT-0"), + ("Etc/GMT-1", "Etc/GMT-1"), + ("Etc/GMT-10", "Etc/GMT-10"), + ("Etc/GMT-11", "Etc/GMT-11"), + ("Etc/GMT-12", "Etc/GMT-12"), + ("Etc/GMT-13", "Etc/GMT-13"), + ("Etc/GMT-14", "Etc/GMT-14"), + ("Etc/GMT-2", "Etc/GMT-2"), + ("Etc/GMT-3", "Etc/GMT-3"), + ("Etc/GMT-4", "Etc/GMT-4"), + ("Etc/GMT-5", "Etc/GMT-5"), + ("Etc/GMT-6", "Etc/GMT-6"), + ("Etc/GMT-7", "Etc/GMT-7"), + ("Etc/GMT-8", "Etc/GMT-8"), + ("Etc/GMT-9", "Etc/GMT-9"), + ("Etc/GMT0", "Etc/GMT0"), + ("Etc/Greenwich", "Etc/Greenwich"), + ("Etc/UCT", "Etc/UCT"), + ("Etc/UTC", "Etc/UTC"), + ("Etc/Universal", "Etc/Universal"), + ("Etc/Zulu", "Etc/Zulu"), + ("Europe/Amsterdam", "Europe/Amsterdam"), + ("Europe/Andorra", "Europe/Andorra"), + ("Europe/Astrakhan", "Europe/Astrakhan"), + ("Europe/Athens", "Europe/Athens"), + ("Europe/Belfast", "Europe/Belfast"), + ("Europe/Belgrade", "Europe/Belgrade"), + ("Europe/Berlin", "Europe/Berlin"), + ("Europe/Bratislava", "Europe/Bratislava"), + ("Europe/Brussels", "Europe/Brussels"), + ("Europe/Bucharest", "Europe/Bucharest"), + ("Europe/Budapest", "Europe/Budapest"), + ("Europe/Busingen", "Europe/Busingen"), + ("Europe/Chisinau", "Europe/Chisinau"), + ("Europe/Copenhagen", "Europe/Copenhagen"), + ("Europe/Dublin", "Europe/Dublin"), + ("Europe/Gibraltar", "Europe/Gibraltar"), + ("Europe/Guernsey", "Europe/Guernsey"), + ("Europe/Helsinki", "Europe/Helsinki"), + ("Europe/Isle_of_Man", "Europe/Isle_of_Man"), + ("Europe/Istanbul", "Europe/Istanbul"), + ("Europe/Jersey", "Europe/Jersey"), + ("Europe/Kaliningrad", "Europe/Kaliningrad"), + ("Europe/Kiev", "Europe/Kiev"), + ("Europe/Kirov", "Europe/Kirov"), + ("Europe/Kyiv", "Europe/Kyiv"), + ("Europe/Lisbon", "Europe/Lisbon"), + ("Europe/Ljubljana", "Europe/Ljubljana"), + ("Europe/London", "Europe/London"), + ("Europe/Luxembourg", "Europe/Luxembourg"), + ("Europe/Madrid", "Europe/Madrid"), + ("Europe/Malta", "Europe/Malta"), + ("Europe/Mariehamn", "Europe/Mariehamn"), + ("Europe/Minsk", "Europe/Minsk"), + ("Europe/Monaco", "Europe/Monaco"), + ("Europe/Moscow", "Europe/Moscow"), + ("Europe/Nicosia", "Europe/Nicosia"), + ("Europe/Oslo", "Europe/Oslo"), + ("Europe/Paris", "Europe/Paris"), + ("Europe/Podgorica", "Europe/Podgorica"), + ("Europe/Prague", "Europe/Prague"), + ("Europe/Riga", "Europe/Riga"), + ("Europe/Rome", "Europe/Rome"), + ("Europe/Samara", "Europe/Samara"), + ("Europe/San_Marino", "Europe/San_Marino"), + ("Europe/Sarajevo", "Europe/Sarajevo"), + ("Europe/Saratov", "Europe/Saratov"), + ("Europe/Simferopol", "Europe/Simferopol"), + ("Europe/Skopje", "Europe/Skopje"), + ("Europe/Sofia", "Europe/Sofia"), + ("Europe/Stockholm", "Europe/Stockholm"), + ("Europe/Tallinn", "Europe/Tallinn"), + ("Europe/Tirane", "Europe/Tirane"), + ("Europe/Tiraspol", "Europe/Tiraspol"), + ("Europe/Ulyanovsk", "Europe/Ulyanovsk"), + ("Europe/Uzhgorod", "Europe/Uzhgorod"), + ("Europe/Vaduz", "Europe/Vaduz"), + ("Europe/Vatican", "Europe/Vatican"), + ("Europe/Vienna", "Europe/Vienna"), + ("Europe/Vilnius", "Europe/Vilnius"), + ("Europe/Volgograd", "Europe/Volgograd"), + ("Europe/Warsaw", "Europe/Warsaw"), + ("Europe/Zagreb", "Europe/Zagreb"), + ("Europe/Zaporozhye", "Europe/Zaporozhye"), + ("Europe/Zurich", "Europe/Zurich"), + ("Factory", "Factory"), + ("GB", "GB"), + ("GB-Eire", "GB-Eire"), + ("GMT", "GMT"), + ("GMT+0", "GMT+0"), + ("GMT-0", "GMT-0"), + ("GMT0", "GMT0"), + ("Greenwich", "Greenwich"), + ("HST", "HST"), + ("Hongkong", "Hongkong"), + ("Iceland", "Iceland"), + ("Indian/Antananarivo", "Indian/Antananarivo"), + ("Indian/Chagos", "Indian/Chagos"), + ("Indian/Christmas", "Indian/Christmas"), + ("Indian/Cocos", "Indian/Cocos"), + ("Indian/Comoro", "Indian/Comoro"), + ("Indian/Kerguelen", "Indian/Kerguelen"), + ("Indian/Mahe", "Indian/Mahe"), + ("Indian/Maldives", "Indian/Maldives"), + ("Indian/Mauritius", "Indian/Mauritius"), + ("Indian/Mayotte", "Indian/Mayotte"), + ("Indian/Reunion", "Indian/Reunion"), + ("Iran", "Iran"), + ("Israel", "Israel"), + ("Jamaica", "Jamaica"), + ("Japan", "Japan"), + ("Kwajalein", "Kwajalein"), + ("Libya", "Libya"), + ("MET", "MET"), + ("MST", "MST"), + ("MST7MDT", "MST7MDT"), + ("Mexico/BajaNorte", "Mexico/BajaNorte"), + ("Mexico/BajaSur", "Mexico/BajaSur"), + ("Mexico/General", "Mexico/General"), + ("NZ", "NZ"), + ("NZ-CHAT", "NZ-CHAT"), + ("Navajo", "Navajo"), + ("PRC", "PRC"), + ("PST8PDT", "PST8PDT"), + ("Pacific/Apia", "Pacific/Apia"), + ("Pacific/Auckland", "Pacific/Auckland"), + ("Pacific/Bougainville", "Pacific/Bougainville"), + ("Pacific/Chatham", "Pacific/Chatham"), + ("Pacific/Chuuk", "Pacific/Chuuk"), + ("Pacific/Easter", "Pacific/Easter"), + ("Pacific/Efate", "Pacific/Efate"), + ("Pacific/Enderbury", "Pacific/Enderbury"), + ("Pacific/Fakaofo", "Pacific/Fakaofo"), + ("Pacific/Fiji", "Pacific/Fiji"), + ("Pacific/Funafuti", "Pacific/Funafuti"), + ("Pacific/Galapagos", "Pacific/Galapagos"), + ("Pacific/Gambier", "Pacific/Gambier"), + ("Pacific/Guadalcanal", "Pacific/Guadalcanal"), + ("Pacific/Guam", "Pacific/Guam"), + ("Pacific/Honolulu", "Pacific/Honolulu"), + ("Pacific/Johnston", "Pacific/Johnston"), + ("Pacific/Kanton", "Pacific/Kanton"), + ("Pacific/Kiritimati", "Pacific/Kiritimati"), + ("Pacific/Kosrae", "Pacific/Kosrae"), + ("Pacific/Kwajalein", "Pacific/Kwajalein"), + ("Pacific/Majuro", "Pacific/Majuro"), + ("Pacific/Marquesas", "Pacific/Marquesas"), + ("Pacific/Midway", "Pacific/Midway"), + ("Pacific/Nauru", "Pacific/Nauru"), + ("Pacific/Niue", "Pacific/Niue"), + ("Pacific/Norfolk", "Pacific/Norfolk"), + ("Pacific/Noumea", "Pacific/Noumea"), + ("Pacific/Pago_Pago", "Pacific/Pago_Pago"), + ("Pacific/Palau", "Pacific/Palau"), + ("Pacific/Pitcairn", "Pacific/Pitcairn"), + ("Pacific/Pohnpei", "Pacific/Pohnpei"), + ("Pacific/Ponape", "Pacific/Ponape"), + ("Pacific/Port_Moresby", "Pacific/Port_Moresby"), + ("Pacific/Rarotonga", "Pacific/Rarotonga"), + ("Pacific/Saipan", "Pacific/Saipan"), + ("Pacific/Samoa", "Pacific/Samoa"), + ("Pacific/Tahiti", "Pacific/Tahiti"), + ("Pacific/Tarawa", "Pacific/Tarawa"), + ("Pacific/Tongatapu", "Pacific/Tongatapu"), + ("Pacific/Truk", "Pacific/Truk"), + ("Pacific/Wake", "Pacific/Wake"), + ("Pacific/Wallis", "Pacific/Wallis"), + ("Pacific/Yap", "Pacific/Yap"), + ("Poland", "Poland"), + ("Portugal", "Portugal"), + ("ROC", "ROC"), + ("ROK", "ROK"), + ("Singapore", "Singapore"), + ("Turkey", "Turkey"), + ("UCT", "UCT"), + ("US/Alaska", "US/Alaska"), + ("US/Aleutian", "US/Aleutian"), + ("US/Arizona", "US/Arizona"), + ("US/Central", "US/Central"), + ("US/East-Indiana", "US/East-Indiana"), + ("US/Eastern", "US/Eastern"), + ("US/Hawaii", "US/Hawaii"), + ("US/Indiana-Starke", "US/Indiana-Starke"), + ("US/Michigan", "US/Michigan"), + ("US/Mountain", "US/Mountain"), + ("US/Pacific", "US/Pacific"), + ("US/Samoa", "US/Samoa"), + ("UTC", "UTC"), + ("Universal", "Universal"), + ("W-SU", "W-SU"), + ("WET", "WET"), + ("Zulu", "Zulu"), + ("localtime", "localtime"), + ], + max_length=255, + null=True, + ), + ), + ] diff --git a/api/tacticalrmm/agents/models.py b/api/tacticalrmm/agents/models.py index 133d157119..21ddfc0f2e 100644 --- a/api/tacticalrmm/agents/models.py +++ b/api/tacticalrmm/agents/models.py @@ -1,4 +1,5 @@ import asyncio +import logging import re from collections import Counter from contextlib import suppress @@ -7,7 +8,6 @@ import msgpack import nats import validators -from asgiref.sync import sync_to_async from django.conf import settings from django.contrib.postgres.fields import ArrayField from django.core.cache import cache @@ -54,6 +54,8 @@ # type helpers Disk = Union[Dict[str, Any], str] +logger = logging.getLogger("trmm") + class Agent(BaseAuditModel): class Meta: @@ -798,9 +800,6 @@ def get_tasks_from_policies(self) -> "List[AutomatedTask]": cache.set(cache_key, tasks, 600) return tasks - def _do_nats_debug(self, agent: "Agent", message: str) -> None: - DebugLog.error(agent=agent, log_type=DebugLogType.AGENT_ISSUES, message=message) - async def nats_cmd( self, data: Dict[Any, Any], timeout: int = 30, wait: bool = True ) -> Any: @@ -822,9 +821,7 @@ async def nats_cmd( ret = msgpack.loads(msg.data) except Exception as e: ret = str(e) - await sync_to_async(self._do_nats_debug, thread_sensitive=False)( - agent=self, message=ret - ) + logger.error(e) await nc.close() return ret diff --git a/api/tacticalrmm/agents/permissions.py b/api/tacticalrmm/agents/permissions.py index 4aa5166c6e..057947aa40 100644 --- a/api/tacticalrmm/agents/permissions.py +++ b/api/tacticalrmm/agents/permissions.py @@ -47,13 +47,6 @@ def has_permission(self, r, view) -> bool: return _has_perm(r, "can_update_agents") -class PingAgentPerms(permissions.BasePermission): - def has_permission(self, r, view) -> bool: - return _has_perm(r, "can_ping_agents") and _has_perm_on_agent( - r.user, view.kwargs["agent_id"] - ) - - class ManageProcPerms(permissions.BasePermission): def has_permission(self, r, view) -> bool: return _has_perm(r, "can_manage_procs") and _has_perm_on_agent( diff --git a/api/tacticalrmm/agents/serializers.py b/api/tacticalrmm/agents/serializers.py index 1a3fb9b5ba..ecb3348b50 100644 --- a/api/tacticalrmm/agents/serializers.py +++ b/api/tacticalrmm/agents/serializers.py @@ -1,7 +1,6 @@ -import pytz from rest_framework import serializers -from tacticalrmm.constants import AGENT_STATUS_ONLINE +from tacticalrmm.constants import AGENT_STATUS_ONLINE, ALL_TIMEZONES from winupdate.serializers import WinUpdatePolicySerializer from .models import Agent, AgentCustomField, AgentHistory, Note @@ -71,7 +70,7 @@ def get_applied_policies(self, obj): return policies def get_all_timezones(self, obj): - return pytz.all_timezones + return ALL_TIMEZONES class Meta: model = Agent diff --git a/api/tacticalrmm/agents/tests/test_agents.py b/api/tacticalrmm/agents/tests/test_agents.py index 0a5a89c644..addcaec0e1 100644 --- a/api/tacticalrmm/agents/tests/test_agents.py +++ b/api/tacticalrmm/agents/tests/test_agents.py @@ -1020,7 +1020,6 @@ def test_agent_actions_permissions(self, nats_cmd, sleep): {"method": "post", "action": "recover", "role": "can_recover_agents"}, {"method": "post", "action": "reboot", "role": "can_reboot_agents"}, {"method": "patch", "action": "reboot", "role": "can_reboot_agents"}, - {"method": "get", "action": "ping", "role": "can_ping_agents"}, {"method": "get", "action": "meshcentral", "role": "can_use_mesh"}, {"method": "post", "action": "meshcentral/recover", "role": "can_use_mesh"}, {"method": "get", "action": "processes", "role": "can_manage_procs"}, diff --git a/api/tacticalrmm/agents/views.py b/api/tacticalrmm/agents/views.py index 45fd989847..48e3f35231 100644 --- a/api/tacticalrmm/agents/views.py +++ b/api/tacticalrmm/agents/views.py @@ -65,7 +65,6 @@ InstallAgentPerms, ManageProcPerms, MeshPerms, - PingAgentPerms, RebootAgentPerms, RecoverAgentPerms, RunBulkPerms, @@ -402,7 +401,7 @@ def update_agents(request): @api_view(["GET"]) -@permission_classes([IsAuthenticated, PingAgentPerms]) +@permission_classes([IsAuthenticated, AgentPerms]) def ping(request, agent_id): agent = get_object_or_404(Agent, agent_id=agent_id) status = AGENT_STATUS_OFFLINE diff --git a/api/tacticalrmm/autotasks/management/commands/remove_orphaned_tasks.py b/api/tacticalrmm/autotasks/management/commands/remove_orphaned_tasks.py index 8820022fe2..35e3b0d25f 100644 --- a/api/tacticalrmm/autotasks/management/commands/remove_orphaned_tasks.py +++ b/api/tacticalrmm/autotasks/management/commands/remove_orphaned_tasks.py @@ -7,10 +7,4 @@ class Command(BaseCommand): help = "Checks for orphaned tasks on all agents and removes them" def handle(self, *args, **kwargs): - remove_orphaned_win_tasks.s() - - self.stdout.write( - self.style.SUCCESS( - "The task has been initiated. Check the Debug Log in the UI for progress." - ) - ) + remove_orphaned_win_tasks() diff --git a/api/tacticalrmm/autotasks/migrations/0039_alter_automatedtask_task_type.py b/api/tacticalrmm/autotasks/migrations/0039_alter_automatedtask_task_type.py new file mode 100644 index 0000000000..c479588ee2 --- /dev/null +++ b/api/tacticalrmm/autotasks/migrations/0039_alter_automatedtask_task_type.py @@ -0,0 +1,18 @@ +# Generated by Django 4.2.7 on 2023-11-23 04:39 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('autotasks', '0038_add_missing_env_vars'), + ] + + operations = [ + migrations.AlterField( + model_name='automatedtask', + name='task_type', + field=models.CharField(choices=[('daily', 'Daily'), ('weekly', 'Weekly'), ('monthly', 'Monthly'), ('monthlydow', 'Monthly Day of Week'), ('checkfailure', 'On Check Failure'), ('manual', 'Manual'), ('runonce', 'Run Once'), ('onboarding', 'Onboarding'), ('scheduled', 'Scheduled')], default='manual', max_length=100), + ), + ] diff --git a/api/tacticalrmm/autotasks/models.py b/api/tacticalrmm/autotasks/models.py index 0389d9a443..c13a89f633 100644 --- a/api/tacticalrmm/autotasks/models.py +++ b/api/tacticalrmm/autotasks/models.py @@ -1,9 +1,9 @@ import asyncio +import logging import random import string from contextlib import suppress from typing import TYPE_CHECKING, Any, Dict, List, Optional, Union -from zoneinfo import ZoneInfo from django.core.cache import cache from django.core.validators import MaxValueValidator, MinValueValidator @@ -14,12 +14,11 @@ from django.utils import timezone as djangotime from core.utils import get_core_settings -from logs.models import BaseAuditModel, DebugLog +from logs.models import BaseAuditModel from tacticalrmm.constants import ( FIELDS_TRIGGER_TASK_UPDATE_AGENT, POLICY_TASK_FIELDS_TO_COPY, AlertSeverity, - DebugLogType, TaskStatus, TaskSyncStatus, TaskType, @@ -46,6 +45,9 @@ def generate_task_name() -> str: return "TacticalRMM_" + "".join(random.choice(chars) for i in range(35)) +logger = logging.getLogger("trmm") + + class AutomatedTask(BaseAuditModel): objects = PermissionQuerySet.as_manager() @@ -209,6 +211,9 @@ def schedule(self) -> Optional[str]: weeks = bitweeks_to_string(self.monthly_weeks_of_month) days = bitdays_to_string(self.run_time_bit_weekdays) return f"Runs on {months} on {weeks} on {days} at {run_time_nice}" + elif self.task_type == TaskType.ONBOARDING: + return "Onboarding: Runs once on task creation." + return None @property def fields_that_trigger_task_update_on_agent(self) -> List[str]: @@ -236,14 +241,12 @@ def create_policy_task( task.save() # agent version >= 1.8.0 - def generate_nats_task_payload( - self, agent: "Optional[Agent]" = None, editing: bool = False - ) -> Dict[str, Any]: + def generate_nats_task_payload(self) -> Dict[str, Any]: task = { "pk": self.pk, "type": "rmm", "name": self.win_task_name, - "overwrite_task": editing, + "overwrite_task": True, "enabled": self.enabled, "trigger": self.task_type if self.task_type != TaskType.CHECK_FAILURE @@ -258,42 +261,32 @@ def generate_nats_task_payload( } if self.task_type in ( - TaskType.RUN_ONCE, TaskType.DAILY, TaskType.WEEKLY, TaskType.MONTHLY, TaskType.MONTHLY_DOW, + TaskType.RUN_ONCE, ): - # set runonce task in future if creating and run_asap_after_missed is set - if ( - not editing - and self.task_type == TaskType.RUN_ONCE - and self.run_asap_after_missed - and agent - and self.run_time_date.replace(tzinfo=ZoneInfo(agent.timezone)) - < djangotime.now().astimezone(ZoneInfo(agent.timezone)) - ): - self.run_time_date = ( - djangotime.now() + djangotime.timedelta(minutes=5) - ).astimezone(ZoneInfo(agent.timezone)) - - task["start_year"] = int(self.run_time_date.strftime("%Y")) - task["start_month"] = int(self.run_time_date.strftime("%-m")) - task["start_day"] = int(self.run_time_date.strftime("%-d")) - task["start_hour"] = int(self.run_time_date.strftime("%-H")) - task["start_min"] = int(self.run_time_date.strftime("%-M")) + if not self.run_time_date: + self.run_time_date = djangotime.now() + + task["start_year"] = self.run_time_date.year + task["start_month"] = self.run_time_date.month + task["start_day"] = self.run_time_date.day + task["start_hour"] = self.run_time_date.hour + task["start_min"] = self.run_time_date.minute if self.expire_date: - task["expire_year"] = int(self.expire_date.strftime("%Y")) - task["expire_month"] = int(self.expire_date.strftime("%-m")) - task["expire_day"] = int(self.expire_date.strftime("%-d")) - task["expire_hour"] = int(self.expire_date.strftime("%-H")) - task["expire_min"] = int(self.expire_date.strftime("%-M")) + task["expire_year"] = self.expire_date.year + task["expire_month"] = self.expire_date.month + task["expire_day"] = self.expire_date.day + task["expire_hour"] = self.expire_date.hour + task["expire_min"] = self.expire_date.minute if self.random_task_delay: task["random_delay"] = convert_to_iso_duration(self.random_task_delay) - if self.task_repetition_interval: + if self.task_repetition_interval and self.task_repetition_duration: task["repetition_interval"] = convert_to_iso_duration( self.task_repetition_interval ) @@ -341,27 +334,24 @@ def create_task_on_agent(self, agent: "Optional[Agent]" = None) -> str: nats_data = { "func": "schedtask", - "schedtaskpayload": self.generate_nats_task_payload(agent), + "schedtaskpayload": self.generate_nats_task_payload(), } + logger.debug(nats_data) - r = asyncio.run(task_result.agent.nats_cmd(nats_data, timeout=5)) + r = asyncio.run(task_result.agent.nats_cmd(nats_data, timeout=10)) if r != "ok": task_result.sync_status = TaskSyncStatus.INITIAL task_result.save(update_fields=["sync_status"]) - DebugLog.warning( - agent=agent, - log_type=DebugLogType.AGENT_ISSUES, - message=f"Unable to create scheduled task {self.name} on {task_result.agent.hostname}. It will be created when the agent checks in.", + logger.error( + f"Unable to create scheduled task {self.name} on {task_result.agent.hostname}: {r}" ) return "timeout" else: task_result.sync_status = TaskSyncStatus.SYNCED task_result.save(update_fields=["sync_status"]) - DebugLog.info( - agent=agent, - log_type=DebugLogType.AGENT_ISSUES, - message=f"{task_result.agent.hostname} task {self.name} was successfully created", + logger.info( + f"{task_result.agent.hostname} task {self.name} was successfully created." ) return "ok" @@ -380,27 +370,24 @@ def modify_task_on_agent(self, agent: "Optional[Agent]" = None) -> str: nats_data = { "func": "schedtask", - "schedtaskpayload": self.generate_nats_task_payload(editing=True), + "schedtaskpayload": self.generate_nats_task_payload(), } + logger.debug(nats_data) - r = asyncio.run(task_result.agent.nats_cmd(nats_data, timeout=5)) + r = asyncio.run(task_result.agent.nats_cmd(nats_data, timeout=10)) if r != "ok": task_result.sync_status = TaskSyncStatus.NOT_SYNCED task_result.save(update_fields=["sync_status"]) - DebugLog.warning( - agent=agent, - log_type=DebugLogType.AGENT_ISSUES, - message=f"Unable to modify scheduled task {self.name} on {task_result.agent.hostname}({task_result.agent.agent_id}). It will try again on next agent checkin", + logger.error( + f"Unable to modify scheduled task {self.name} on {task_result.agent.hostname}: {r}" ) return "timeout" else: task_result.sync_status = TaskSyncStatus.SYNCED task_result.save(update_fields=["sync_status"]) - DebugLog.info( - agent=agent, - log_type=DebugLogType.AGENT_ISSUES, - message=f"{task_result.agent.hostname} task {self.name} was successfully modified", + logger.info( + f"{task_result.agent.hostname} task {self.name} was successfully modified." ) return "ok" @@ -429,20 +416,13 @@ def delete_task_on_agent(self, agent: "Optional[Agent]" = None) -> str: with suppress(DatabaseError): task_result.save(update_fields=["sync_status"]) - DebugLog.warning( - agent=agent, - log_type=DebugLogType.AGENT_ISSUES, - message=f"{task_result.agent.hostname} task {self.name} will be deleted on next checkin", + logger.error( + f"Unable to delete task {self.name} on {task_result.agent.hostname}: {r}" ) return "timeout" else: self.delete() - DebugLog.info( - agent=agent, - log_type=DebugLogType.AGENT_ISSUES, - message=f"{task_result.agent.hostname}({task_result.agent.agent_id}) task {self.name} was deleted", - ) - + logger.info(f"{task_result.agent.hostname} task {self.name} was deleted.") return "ok" def run_win_task(self, agent: "Optional[Agent]" = None) -> str: diff --git a/api/tacticalrmm/autotasks/tests.py b/api/tacticalrmm/autotasks/tests.py index ef44eded7d..e28fb44ed9 100644 --- a/api/tacticalrmm/autotasks/tests.py +++ b/api/tacticalrmm/autotasks/tests.py @@ -417,7 +417,7 @@ def test_create_win_task_schedule(self, nats_cmd): "pk": task1.pk, "type": "rmm", "name": task1.win_task_name, - "overwrite_task": False, + "overwrite_task": True, "enabled": True, "trigger": "daily", "multiple_instances": 1, @@ -431,7 +431,7 @@ def test_create_win_task_schedule(self, nats_cmd): "day_interval": 1, }, }, - timeout=5, + timeout=10, ) nats_cmd.reset_mock() self.assertEqual( @@ -470,7 +470,7 @@ def test_create_win_task_schedule(self, nats_cmd): "pk": task1.pk, "type": "rmm", "name": task1.win_task_name, - "overwrite_task": False, + "overwrite_task": True, "enabled": True, "trigger": "weekly", "multiple_instances": 2, @@ -490,7 +490,7 @@ def test_create_win_task_schedule(self, nats_cmd): "days_of_week": 127, }, }, - timeout=5, + timeout=10, ) nats_cmd.reset_mock() @@ -518,7 +518,7 @@ def test_create_win_task_schedule(self, nats_cmd): "pk": task1.pk, "type": "rmm", "name": task1.win_task_name, - "overwrite_task": False, + "overwrite_task": True, "enabled": True, "trigger": "monthly", "multiple_instances": 1, @@ -538,7 +538,7 @@ def test_create_win_task_schedule(self, nats_cmd): "months_of_year": 1024, }, }, - timeout=5, + timeout=10, ) nats_cmd.reset_mock() @@ -562,7 +562,7 @@ def test_create_win_task_schedule(self, nats_cmd): "pk": task1.pk, "type": "rmm", "name": task1.win_task_name, - "overwrite_task": False, + "overwrite_task": True, "enabled": True, "trigger": "monthlydow", "multiple_instances": 1, @@ -578,7 +578,7 @@ def test_create_win_task_schedule(self, nats_cmd): "weeks_of_month": 3, }, }, - timeout=5, + timeout=10, ) nats_cmd.reset_mock() @@ -600,7 +600,7 @@ def test_create_win_task_schedule(self, nats_cmd): "pk": task1.pk, "type": "rmm", "name": task1.win_task_name, - "overwrite_task": False, + "overwrite_task": True, "enabled": True, "trigger": "runonce", "multiple_instances": 1, @@ -613,39 +613,10 @@ def test_create_win_task_schedule(self, nats_cmd): "start_min": int(task1.run_time_date.strftime("%-M")), }, }, - timeout=5, + timeout=10, ) nats_cmd.reset_mock() - # test runonce with date in the past - task1 = baker.make( - "autotasks.AutomatedTask", - agent=agent, - name="test task 3", - task_type=TaskType.RUN_ONCE, - run_asap_after_missed=True, - run_time_date=djangotime.datetime(2018, 6, 1, 23, 23, 23), - ) - nats_cmd.return_value = "ok" - create_win_task_schedule(pk=task1.pk) - nats_cmd.assert_called() - - # check if task is scheduled for at most 5min in the future - _, args, _ = nats_cmd.mock_calls[0] - - current_minute = int(djangotime.now().strftime("%-M")) - - if current_minute >= 55 and current_minute < 60: - self.assertLess( - args[0]["schedtaskpayload"]["start_min"], - int(djangotime.now().strftime("%-M")), - ) - else: - self.assertGreater( - args[0]["schedtaskpayload"]["start_min"], - int(djangotime.now().strftime("%-M")), - ) - # test checkfailure task nats_cmd.reset_mock() check = baker.make_recipe("checks.diskspace_check", agent=agent) @@ -665,7 +636,7 @@ def test_create_win_task_schedule(self, nats_cmd): "pk": task1.pk, "type": "rmm", "name": task1.win_task_name, - "overwrite_task": False, + "overwrite_task": True, "enabled": True, "trigger": "manual", "multiple_instances": 1, @@ -673,7 +644,7 @@ def test_create_win_task_schedule(self, nats_cmd): "start_when_available": False, }, }, - timeout=5, + timeout=10, ) nats_cmd.reset_mock() @@ -692,7 +663,7 @@ def test_create_win_task_schedule(self, nats_cmd): "pk": task1.pk, "type": "rmm", "name": task1.win_task_name, - "overwrite_task": False, + "overwrite_task": True, "enabled": True, "trigger": "manual", "multiple_instances": 1, @@ -700,7 +671,7 @@ def test_create_win_task_schedule(self, nats_cmd): "start_when_available": False, }, }, - timeout=5, + timeout=10, ) diff --git a/api/tacticalrmm/autotasks/views.py b/api/tacticalrmm/autotasks/views.py index 7e3bb0e0a9..716d60eac0 100644 --- a/api/tacticalrmm/autotasks/views.py +++ b/api/tacticalrmm/autotasks/views.py @@ -1,4 +1,5 @@ from django.shortcuts import get_object_or_404 +from packaging import version as pyver from rest_framework.exceptions import PermissionDenied from rest_framework.permissions import IsAuthenticated from rest_framework.response import Response @@ -6,6 +7,8 @@ from agents.models import Agent from automation.models import Policy +from tacticalrmm.constants import TaskType +from tacticalrmm.helpers import notify_error from tacticalrmm.permissions import _has_perm_on_agent from .models import AutomatedTask @@ -40,6 +43,11 @@ def post(self, request): if not _has_perm_on_agent(request.user, agent.agent_id): raise PermissionDenied() + if data["task_type"] == TaskType.ONBOARDING and pyver.parse( + agent.version + ) < pyver.parse("2.6.0"): + return notify_error("Onboarding tasks require agent >= 2.6.0") + data["agent"] = agent.pk serializer = TaskSerializer(data=data) diff --git a/api/tacticalrmm/core/migrations/0038_alter_coresettings_default_time_zone.py b/api/tacticalrmm/core/migrations/0038_alter_coresettings_default_time_zone.py new file mode 100644 index 0000000000..c1d238c464 --- /dev/null +++ b/api/tacticalrmm/core/migrations/0038_alter_coresettings_default_time_zone.py @@ -0,0 +1,632 @@ +# Generated by Django 4.2.7 on 2023-11-09 19:56 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + dependencies = [ + ("core", "0037_coresettings_open_ai_model_and_more"), + ] + + operations = [ + migrations.AlterField( + model_name="coresettings", + name="default_time_zone", + field=models.CharField( + choices=[ + ("Africa/Abidjan", "Africa/Abidjan"), + ("Africa/Accra", "Africa/Accra"), + ("Africa/Addis_Ababa", "Africa/Addis_Ababa"), + ("Africa/Algiers", "Africa/Algiers"), + ("Africa/Asmara", "Africa/Asmara"), + ("Africa/Asmera", "Africa/Asmera"), + ("Africa/Bamako", "Africa/Bamako"), + ("Africa/Bangui", "Africa/Bangui"), + ("Africa/Banjul", "Africa/Banjul"), + ("Africa/Bissau", "Africa/Bissau"), + ("Africa/Blantyre", "Africa/Blantyre"), + ("Africa/Brazzaville", "Africa/Brazzaville"), + ("Africa/Bujumbura", "Africa/Bujumbura"), + ("Africa/Cairo", "Africa/Cairo"), + ("Africa/Casablanca", "Africa/Casablanca"), + ("Africa/Ceuta", "Africa/Ceuta"), + ("Africa/Conakry", "Africa/Conakry"), + ("Africa/Dakar", "Africa/Dakar"), + ("Africa/Dar_es_Salaam", "Africa/Dar_es_Salaam"), + ("Africa/Djibouti", "Africa/Djibouti"), + ("Africa/Douala", "Africa/Douala"), + ("Africa/El_Aaiun", "Africa/El_Aaiun"), + ("Africa/Freetown", "Africa/Freetown"), + ("Africa/Gaborone", "Africa/Gaborone"), + ("Africa/Harare", "Africa/Harare"), + ("Africa/Johannesburg", "Africa/Johannesburg"), + ("Africa/Juba", "Africa/Juba"), + ("Africa/Kampala", "Africa/Kampala"), + ("Africa/Khartoum", "Africa/Khartoum"), + ("Africa/Kigali", "Africa/Kigali"), + ("Africa/Kinshasa", "Africa/Kinshasa"), + ("Africa/Lagos", "Africa/Lagos"), + ("Africa/Libreville", "Africa/Libreville"), + ("Africa/Lome", "Africa/Lome"), + ("Africa/Luanda", "Africa/Luanda"), + ("Africa/Lubumbashi", "Africa/Lubumbashi"), + ("Africa/Lusaka", "Africa/Lusaka"), + ("Africa/Malabo", "Africa/Malabo"), + ("Africa/Maputo", "Africa/Maputo"), + ("Africa/Maseru", "Africa/Maseru"), + ("Africa/Mbabane", "Africa/Mbabane"), + ("Africa/Mogadishu", "Africa/Mogadishu"), + ("Africa/Monrovia", "Africa/Monrovia"), + ("Africa/Nairobi", "Africa/Nairobi"), + ("Africa/Ndjamena", "Africa/Ndjamena"), + ("Africa/Niamey", "Africa/Niamey"), + ("Africa/Nouakchott", "Africa/Nouakchott"), + ("Africa/Ouagadougou", "Africa/Ouagadougou"), + ("Africa/Porto-Novo", "Africa/Porto-Novo"), + ("Africa/Sao_Tome", "Africa/Sao_Tome"), + ("Africa/Timbuktu", "Africa/Timbuktu"), + ("Africa/Tripoli", "Africa/Tripoli"), + ("Africa/Tunis", "Africa/Tunis"), + ("Africa/Windhoek", "Africa/Windhoek"), + ("America/Adak", "America/Adak"), + ("America/Anchorage", "America/Anchorage"), + ("America/Anguilla", "America/Anguilla"), + ("America/Antigua", "America/Antigua"), + ("America/Araguaina", "America/Araguaina"), + ( + "America/Argentina/Buenos_Aires", + "America/Argentina/Buenos_Aires", + ), + ("America/Argentina/Catamarca", "America/Argentina/Catamarca"), + ( + "America/Argentina/ComodRivadavia", + "America/Argentina/ComodRivadavia", + ), + ("America/Argentina/Cordoba", "America/Argentina/Cordoba"), + ("America/Argentina/Jujuy", "America/Argentina/Jujuy"), + ("America/Argentina/La_Rioja", "America/Argentina/La_Rioja"), + ("America/Argentina/Mendoza", "America/Argentina/Mendoza"), + ( + "America/Argentina/Rio_Gallegos", + "America/Argentina/Rio_Gallegos", + ), + ("America/Argentina/Salta", "America/Argentina/Salta"), + ("America/Argentina/San_Juan", "America/Argentina/San_Juan"), + ("America/Argentina/San_Luis", "America/Argentina/San_Luis"), + ("America/Argentina/Tucuman", "America/Argentina/Tucuman"), + ("America/Argentina/Ushuaia", "America/Argentina/Ushuaia"), + ("America/Aruba", "America/Aruba"), + ("America/Asuncion", "America/Asuncion"), + ("America/Atikokan", "America/Atikokan"), + ("America/Atka", "America/Atka"), + ("America/Bahia", "America/Bahia"), + ("America/Bahia_Banderas", "America/Bahia_Banderas"), + ("America/Barbados", "America/Barbados"), + ("America/Belem", "America/Belem"), + ("America/Belize", "America/Belize"), + ("America/Blanc-Sablon", "America/Blanc-Sablon"), + ("America/Boa_Vista", "America/Boa_Vista"), + ("America/Bogota", "America/Bogota"), + ("America/Boise", "America/Boise"), + ("America/Buenos_Aires", "America/Buenos_Aires"), + ("America/Cambridge_Bay", "America/Cambridge_Bay"), + ("America/Campo_Grande", "America/Campo_Grande"), + ("America/Cancun", "America/Cancun"), + ("America/Caracas", "America/Caracas"), + ("America/Catamarca", "America/Catamarca"), + ("America/Cayenne", "America/Cayenne"), + ("America/Cayman", "America/Cayman"), + ("America/Chicago", "America/Chicago"), + ("America/Chihuahua", "America/Chihuahua"), + ("America/Ciudad_Juarez", "America/Ciudad_Juarez"), + ("America/Coral_Harbour", "America/Coral_Harbour"), + ("America/Cordoba", "America/Cordoba"), + ("America/Costa_Rica", "America/Costa_Rica"), + ("America/Creston", "America/Creston"), + ("America/Cuiaba", "America/Cuiaba"), + ("America/Curacao", "America/Curacao"), + ("America/Danmarkshavn", "America/Danmarkshavn"), + ("America/Dawson", "America/Dawson"), + ("America/Dawson_Creek", "America/Dawson_Creek"), + ("America/Denver", "America/Denver"), + ("America/Detroit", "America/Detroit"), + ("America/Dominica", "America/Dominica"), + ("America/Edmonton", "America/Edmonton"), + ("America/Eirunepe", "America/Eirunepe"), + ("America/El_Salvador", "America/El_Salvador"), + ("America/Ensenada", "America/Ensenada"), + ("America/Fort_Nelson", "America/Fort_Nelson"), + ("America/Fort_Wayne", "America/Fort_Wayne"), + ("America/Fortaleza", "America/Fortaleza"), + ("America/Glace_Bay", "America/Glace_Bay"), + ("America/Godthab", "America/Godthab"), + ("America/Goose_Bay", "America/Goose_Bay"), + ("America/Grand_Turk", "America/Grand_Turk"), + ("America/Grenada", "America/Grenada"), + ("America/Guadeloupe", "America/Guadeloupe"), + ("America/Guatemala", "America/Guatemala"), + ("America/Guayaquil", "America/Guayaquil"), + ("America/Guyana", "America/Guyana"), + ("America/Halifax", "America/Halifax"), + ("America/Havana", "America/Havana"), + ("America/Hermosillo", "America/Hermosillo"), + ("America/Indiana/Indianapolis", "America/Indiana/Indianapolis"), + ("America/Indiana/Knox", "America/Indiana/Knox"), + ("America/Indiana/Marengo", "America/Indiana/Marengo"), + ("America/Indiana/Petersburg", "America/Indiana/Petersburg"), + ("America/Indiana/Tell_City", "America/Indiana/Tell_City"), + ("America/Indiana/Vevay", "America/Indiana/Vevay"), + ("America/Indiana/Vincennes", "America/Indiana/Vincennes"), + ("America/Indiana/Winamac", "America/Indiana/Winamac"), + ("America/Indianapolis", "America/Indianapolis"), + ("America/Inuvik", "America/Inuvik"), + ("America/Iqaluit", "America/Iqaluit"), + ("America/Jamaica", "America/Jamaica"), + ("America/Jujuy", "America/Jujuy"), + ("America/Juneau", "America/Juneau"), + ("America/Kentucky/Louisville", "America/Kentucky/Louisville"), + ("America/Kentucky/Monticello", "America/Kentucky/Monticello"), + ("America/Knox_IN", "America/Knox_IN"), + ("America/Kralendijk", "America/Kralendijk"), + ("America/La_Paz", "America/La_Paz"), + ("America/Lima", "America/Lima"), + ("America/Los_Angeles", "America/Los_Angeles"), + ("America/Louisville", "America/Louisville"), + ("America/Lower_Princes", "America/Lower_Princes"), + ("America/Maceio", "America/Maceio"), + ("America/Managua", "America/Managua"), + ("America/Manaus", "America/Manaus"), + ("America/Marigot", "America/Marigot"), + ("America/Martinique", "America/Martinique"), + ("America/Matamoros", "America/Matamoros"), + ("America/Mazatlan", "America/Mazatlan"), + ("America/Mendoza", "America/Mendoza"), + ("America/Menominee", "America/Menominee"), + ("America/Merida", "America/Merida"), + ("America/Metlakatla", "America/Metlakatla"), + ("America/Mexico_City", "America/Mexico_City"), + ("America/Miquelon", "America/Miquelon"), + ("America/Moncton", "America/Moncton"), + ("America/Monterrey", "America/Monterrey"), + ("America/Montevideo", "America/Montevideo"), + ("America/Montreal", "America/Montreal"), + ("America/Montserrat", "America/Montserrat"), + ("America/Nassau", "America/Nassau"), + ("America/New_York", "America/New_York"), + ("America/Nipigon", "America/Nipigon"), + ("America/Nome", "America/Nome"), + ("America/Noronha", "America/Noronha"), + ("America/North_Dakota/Beulah", "America/North_Dakota/Beulah"), + ("America/North_Dakota/Center", "America/North_Dakota/Center"), + ( + "America/North_Dakota/New_Salem", + "America/North_Dakota/New_Salem", + ), + ("America/Nuuk", "America/Nuuk"), + ("America/Ojinaga", "America/Ojinaga"), + ("America/Panama", "America/Panama"), + ("America/Pangnirtung", "America/Pangnirtung"), + ("America/Paramaribo", "America/Paramaribo"), + ("America/Phoenix", "America/Phoenix"), + ("America/Port-au-Prince", "America/Port-au-Prince"), + ("America/Port_of_Spain", "America/Port_of_Spain"), + ("America/Porto_Acre", "America/Porto_Acre"), + ("America/Porto_Velho", "America/Porto_Velho"), + ("America/Puerto_Rico", "America/Puerto_Rico"), + ("America/Punta_Arenas", "America/Punta_Arenas"), + ("America/Rainy_River", "America/Rainy_River"), + ("America/Rankin_Inlet", "America/Rankin_Inlet"), + ("America/Recife", "America/Recife"), + ("America/Regina", "America/Regina"), + ("America/Resolute", "America/Resolute"), + ("America/Rio_Branco", "America/Rio_Branco"), + ("America/Rosario", "America/Rosario"), + ("America/Santa_Isabel", "America/Santa_Isabel"), + ("America/Santarem", "America/Santarem"), + ("America/Santiago", "America/Santiago"), + ("America/Santo_Domingo", "America/Santo_Domingo"), + ("America/Sao_Paulo", "America/Sao_Paulo"), + ("America/Scoresbysund", "America/Scoresbysund"), + ("America/Shiprock", "America/Shiprock"), + ("America/Sitka", "America/Sitka"), + ("America/St_Barthelemy", "America/St_Barthelemy"), + ("America/St_Johns", "America/St_Johns"), + ("America/St_Kitts", "America/St_Kitts"), + ("America/St_Lucia", "America/St_Lucia"), + ("America/St_Thomas", "America/St_Thomas"), + ("America/St_Vincent", "America/St_Vincent"), + ("America/Swift_Current", "America/Swift_Current"), + ("America/Tegucigalpa", "America/Tegucigalpa"), + ("America/Thule", "America/Thule"), + ("America/Thunder_Bay", "America/Thunder_Bay"), + ("America/Tijuana", "America/Tijuana"), + ("America/Toronto", "America/Toronto"), + ("America/Tortola", "America/Tortola"), + ("America/Vancouver", "America/Vancouver"), + ("America/Virgin", "America/Virgin"), + ("America/Whitehorse", "America/Whitehorse"), + ("America/Winnipeg", "America/Winnipeg"), + ("America/Yakutat", "America/Yakutat"), + ("America/Yellowknife", "America/Yellowknife"), + ("Antarctica/Casey", "Antarctica/Casey"), + ("Antarctica/Davis", "Antarctica/Davis"), + ("Antarctica/DumontDUrville", "Antarctica/DumontDUrville"), + ("Antarctica/Macquarie", "Antarctica/Macquarie"), + ("Antarctica/Mawson", "Antarctica/Mawson"), + ("Antarctica/McMurdo", "Antarctica/McMurdo"), + ("Antarctica/Palmer", "Antarctica/Palmer"), + ("Antarctica/Rothera", "Antarctica/Rothera"), + ("Antarctica/South_Pole", "Antarctica/South_Pole"), + ("Antarctica/Syowa", "Antarctica/Syowa"), + ("Antarctica/Troll", "Antarctica/Troll"), + ("Antarctica/Vostok", "Antarctica/Vostok"), + ("Arctic/Longyearbyen", "Arctic/Longyearbyen"), + ("Asia/Aden", "Asia/Aden"), + ("Asia/Almaty", "Asia/Almaty"), + ("Asia/Amman", "Asia/Amman"), + ("Asia/Anadyr", "Asia/Anadyr"), + ("Asia/Aqtau", "Asia/Aqtau"), + ("Asia/Aqtobe", "Asia/Aqtobe"), + ("Asia/Ashgabat", "Asia/Ashgabat"), + ("Asia/Ashkhabad", "Asia/Ashkhabad"), + ("Asia/Atyrau", "Asia/Atyrau"), + ("Asia/Baghdad", "Asia/Baghdad"), + ("Asia/Bahrain", "Asia/Bahrain"), + ("Asia/Baku", "Asia/Baku"), + ("Asia/Bangkok", "Asia/Bangkok"), + ("Asia/Barnaul", "Asia/Barnaul"), + ("Asia/Beirut", "Asia/Beirut"), + ("Asia/Bishkek", "Asia/Bishkek"), + ("Asia/Brunei", "Asia/Brunei"), + ("Asia/Calcutta", "Asia/Calcutta"), + ("Asia/Chita", "Asia/Chita"), + ("Asia/Choibalsan", "Asia/Choibalsan"), + ("Asia/Chongqing", "Asia/Chongqing"), + ("Asia/Chungking", "Asia/Chungking"), + ("Asia/Colombo", "Asia/Colombo"), + ("Asia/Dacca", "Asia/Dacca"), + ("Asia/Damascus", "Asia/Damascus"), + ("Asia/Dhaka", "Asia/Dhaka"), + ("Asia/Dili", "Asia/Dili"), + ("Asia/Dubai", "Asia/Dubai"), + ("Asia/Dushanbe", "Asia/Dushanbe"), + ("Asia/Famagusta", "Asia/Famagusta"), + ("Asia/Gaza", "Asia/Gaza"), + ("Asia/Harbin", "Asia/Harbin"), + ("Asia/Hebron", "Asia/Hebron"), + ("Asia/Ho_Chi_Minh", "Asia/Ho_Chi_Minh"), + ("Asia/Hong_Kong", "Asia/Hong_Kong"), + ("Asia/Hovd", "Asia/Hovd"), + ("Asia/Irkutsk", "Asia/Irkutsk"), + ("Asia/Istanbul", "Asia/Istanbul"), + ("Asia/Jakarta", "Asia/Jakarta"), + ("Asia/Jayapura", "Asia/Jayapura"), + ("Asia/Jerusalem", "Asia/Jerusalem"), + ("Asia/Kabul", "Asia/Kabul"), + ("Asia/Kamchatka", "Asia/Kamchatka"), + ("Asia/Karachi", "Asia/Karachi"), + ("Asia/Kashgar", "Asia/Kashgar"), + ("Asia/Kathmandu", "Asia/Kathmandu"), + ("Asia/Katmandu", "Asia/Katmandu"), + ("Asia/Khandyga", "Asia/Khandyga"), + ("Asia/Kolkata", "Asia/Kolkata"), + ("Asia/Krasnoyarsk", "Asia/Krasnoyarsk"), + ("Asia/Kuala_Lumpur", "Asia/Kuala_Lumpur"), + ("Asia/Kuching", "Asia/Kuching"), + ("Asia/Kuwait", "Asia/Kuwait"), + ("Asia/Macao", "Asia/Macao"), + ("Asia/Macau", "Asia/Macau"), + ("Asia/Magadan", "Asia/Magadan"), + ("Asia/Makassar", "Asia/Makassar"), + ("Asia/Manila", "Asia/Manila"), + ("Asia/Muscat", "Asia/Muscat"), + ("Asia/Nicosia", "Asia/Nicosia"), + ("Asia/Novokuznetsk", "Asia/Novokuznetsk"), + ("Asia/Novosibirsk", "Asia/Novosibirsk"), + ("Asia/Omsk", "Asia/Omsk"), + ("Asia/Oral", "Asia/Oral"), + ("Asia/Phnom_Penh", "Asia/Phnom_Penh"), + ("Asia/Pontianak", "Asia/Pontianak"), + ("Asia/Pyongyang", "Asia/Pyongyang"), + ("Asia/Qatar", "Asia/Qatar"), + ("Asia/Qostanay", "Asia/Qostanay"), + ("Asia/Qyzylorda", "Asia/Qyzylorda"), + ("Asia/Rangoon", "Asia/Rangoon"), + ("Asia/Riyadh", "Asia/Riyadh"), + ("Asia/Saigon", "Asia/Saigon"), + ("Asia/Sakhalin", "Asia/Sakhalin"), + ("Asia/Samarkand", "Asia/Samarkand"), + ("Asia/Seoul", "Asia/Seoul"), + ("Asia/Shanghai", "Asia/Shanghai"), + ("Asia/Singapore", "Asia/Singapore"), + ("Asia/Srednekolymsk", "Asia/Srednekolymsk"), + ("Asia/Taipei", "Asia/Taipei"), + ("Asia/Tashkent", "Asia/Tashkent"), + ("Asia/Tbilisi", "Asia/Tbilisi"), + ("Asia/Tehran", "Asia/Tehran"), + ("Asia/Tel_Aviv", "Asia/Tel_Aviv"), + ("Asia/Thimbu", "Asia/Thimbu"), + ("Asia/Thimphu", "Asia/Thimphu"), + ("Asia/Tokyo", "Asia/Tokyo"), + ("Asia/Tomsk", "Asia/Tomsk"), + ("Asia/Ujung_Pandang", "Asia/Ujung_Pandang"), + ("Asia/Ulaanbaatar", "Asia/Ulaanbaatar"), + ("Asia/Ulan_Bator", "Asia/Ulan_Bator"), + ("Asia/Urumqi", "Asia/Urumqi"), + ("Asia/Ust-Nera", "Asia/Ust-Nera"), + ("Asia/Vientiane", "Asia/Vientiane"), + ("Asia/Vladivostok", "Asia/Vladivostok"), + ("Asia/Yakutsk", "Asia/Yakutsk"), + ("Asia/Yangon", "Asia/Yangon"), + ("Asia/Yekaterinburg", "Asia/Yekaterinburg"), + ("Asia/Yerevan", "Asia/Yerevan"), + ("Atlantic/Azores", "Atlantic/Azores"), + ("Atlantic/Bermuda", "Atlantic/Bermuda"), + ("Atlantic/Canary", "Atlantic/Canary"), + ("Atlantic/Cape_Verde", "Atlantic/Cape_Verde"), + ("Atlantic/Faeroe", "Atlantic/Faeroe"), + ("Atlantic/Faroe", "Atlantic/Faroe"), + ("Atlantic/Jan_Mayen", "Atlantic/Jan_Mayen"), + ("Atlantic/Madeira", "Atlantic/Madeira"), + ("Atlantic/Reykjavik", "Atlantic/Reykjavik"), + ("Atlantic/South_Georgia", "Atlantic/South_Georgia"), + ("Atlantic/St_Helena", "Atlantic/St_Helena"), + ("Atlantic/Stanley", "Atlantic/Stanley"), + ("Australia/ACT", "Australia/ACT"), + ("Australia/Adelaide", "Australia/Adelaide"), + ("Australia/Brisbane", "Australia/Brisbane"), + ("Australia/Broken_Hill", "Australia/Broken_Hill"), + ("Australia/Canberra", "Australia/Canberra"), + ("Australia/Currie", "Australia/Currie"), + ("Australia/Darwin", "Australia/Darwin"), + ("Australia/Eucla", "Australia/Eucla"), + ("Australia/Hobart", "Australia/Hobart"), + ("Australia/LHI", "Australia/LHI"), + ("Australia/Lindeman", "Australia/Lindeman"), + ("Australia/Lord_Howe", "Australia/Lord_Howe"), + ("Australia/Melbourne", "Australia/Melbourne"), + ("Australia/NSW", "Australia/NSW"), + ("Australia/North", "Australia/North"), + ("Australia/Perth", "Australia/Perth"), + ("Australia/Queensland", "Australia/Queensland"), + ("Australia/South", "Australia/South"), + ("Australia/Sydney", "Australia/Sydney"), + ("Australia/Tasmania", "Australia/Tasmania"), + ("Australia/Victoria", "Australia/Victoria"), + ("Australia/West", "Australia/West"), + ("Australia/Yancowinna", "Australia/Yancowinna"), + ("Brazil/Acre", "Brazil/Acre"), + ("Brazil/DeNoronha", "Brazil/DeNoronha"), + ("Brazil/East", "Brazil/East"), + ("Brazil/West", "Brazil/West"), + ("CET", "CET"), + ("CST6CDT", "CST6CDT"), + ("Canada/Atlantic", "Canada/Atlantic"), + ("Canada/Central", "Canada/Central"), + ("Canada/Eastern", "Canada/Eastern"), + ("Canada/Mountain", "Canada/Mountain"), + ("Canada/Newfoundland", "Canada/Newfoundland"), + ("Canada/Pacific", "Canada/Pacific"), + ("Canada/Saskatchewan", "Canada/Saskatchewan"), + ("Canada/Yukon", "Canada/Yukon"), + ("Chile/Continental", "Chile/Continental"), + ("Chile/EasterIsland", "Chile/EasterIsland"), + ("Cuba", "Cuba"), + ("EET", "EET"), + ("EST", "EST"), + ("EST5EDT", "EST5EDT"), + ("Egypt", "Egypt"), + ("Eire", "Eire"), + ("Etc/GMT", "Etc/GMT"), + ("Etc/GMT+0", "Etc/GMT+0"), + ("Etc/GMT+1", "Etc/GMT+1"), + ("Etc/GMT+10", "Etc/GMT+10"), + ("Etc/GMT+11", "Etc/GMT+11"), + ("Etc/GMT+12", "Etc/GMT+12"), + ("Etc/GMT+2", "Etc/GMT+2"), + ("Etc/GMT+3", "Etc/GMT+3"), + ("Etc/GMT+4", "Etc/GMT+4"), + ("Etc/GMT+5", "Etc/GMT+5"), + ("Etc/GMT+6", "Etc/GMT+6"), + ("Etc/GMT+7", "Etc/GMT+7"), + ("Etc/GMT+8", "Etc/GMT+8"), + ("Etc/GMT+9", "Etc/GMT+9"), + ("Etc/GMT-0", "Etc/GMT-0"), + ("Etc/GMT-1", "Etc/GMT-1"), + ("Etc/GMT-10", "Etc/GMT-10"), + ("Etc/GMT-11", "Etc/GMT-11"), + ("Etc/GMT-12", "Etc/GMT-12"), + ("Etc/GMT-13", "Etc/GMT-13"), + ("Etc/GMT-14", "Etc/GMT-14"), + ("Etc/GMT-2", "Etc/GMT-2"), + ("Etc/GMT-3", "Etc/GMT-3"), + ("Etc/GMT-4", "Etc/GMT-4"), + ("Etc/GMT-5", "Etc/GMT-5"), + ("Etc/GMT-6", "Etc/GMT-6"), + ("Etc/GMT-7", "Etc/GMT-7"), + ("Etc/GMT-8", "Etc/GMT-8"), + ("Etc/GMT-9", "Etc/GMT-9"), + ("Etc/GMT0", "Etc/GMT0"), + ("Etc/Greenwich", "Etc/Greenwich"), + ("Etc/UCT", "Etc/UCT"), + ("Etc/UTC", "Etc/UTC"), + ("Etc/Universal", "Etc/Universal"), + ("Etc/Zulu", "Etc/Zulu"), + ("Europe/Amsterdam", "Europe/Amsterdam"), + ("Europe/Andorra", "Europe/Andorra"), + ("Europe/Astrakhan", "Europe/Astrakhan"), + ("Europe/Athens", "Europe/Athens"), + ("Europe/Belfast", "Europe/Belfast"), + ("Europe/Belgrade", "Europe/Belgrade"), + ("Europe/Berlin", "Europe/Berlin"), + ("Europe/Bratislava", "Europe/Bratislava"), + ("Europe/Brussels", "Europe/Brussels"), + ("Europe/Bucharest", "Europe/Bucharest"), + ("Europe/Budapest", "Europe/Budapest"), + ("Europe/Busingen", "Europe/Busingen"), + ("Europe/Chisinau", "Europe/Chisinau"), + ("Europe/Copenhagen", "Europe/Copenhagen"), + ("Europe/Dublin", "Europe/Dublin"), + ("Europe/Gibraltar", "Europe/Gibraltar"), + ("Europe/Guernsey", "Europe/Guernsey"), + ("Europe/Helsinki", "Europe/Helsinki"), + ("Europe/Isle_of_Man", "Europe/Isle_of_Man"), + ("Europe/Istanbul", "Europe/Istanbul"), + ("Europe/Jersey", "Europe/Jersey"), + ("Europe/Kaliningrad", "Europe/Kaliningrad"), + ("Europe/Kiev", "Europe/Kiev"), + ("Europe/Kirov", "Europe/Kirov"), + ("Europe/Kyiv", "Europe/Kyiv"), + ("Europe/Lisbon", "Europe/Lisbon"), + ("Europe/Ljubljana", "Europe/Ljubljana"), + ("Europe/London", "Europe/London"), + ("Europe/Luxembourg", "Europe/Luxembourg"), + ("Europe/Madrid", "Europe/Madrid"), + ("Europe/Malta", "Europe/Malta"), + ("Europe/Mariehamn", "Europe/Mariehamn"), + ("Europe/Minsk", "Europe/Minsk"), + ("Europe/Monaco", "Europe/Monaco"), + ("Europe/Moscow", "Europe/Moscow"), + ("Europe/Nicosia", "Europe/Nicosia"), + ("Europe/Oslo", "Europe/Oslo"), + ("Europe/Paris", "Europe/Paris"), + ("Europe/Podgorica", "Europe/Podgorica"), + ("Europe/Prague", "Europe/Prague"), + ("Europe/Riga", "Europe/Riga"), + ("Europe/Rome", "Europe/Rome"), + ("Europe/Samara", "Europe/Samara"), + ("Europe/San_Marino", "Europe/San_Marino"), + ("Europe/Sarajevo", "Europe/Sarajevo"), + ("Europe/Saratov", "Europe/Saratov"), + ("Europe/Simferopol", "Europe/Simferopol"), + ("Europe/Skopje", "Europe/Skopje"), + ("Europe/Sofia", "Europe/Sofia"), + ("Europe/Stockholm", "Europe/Stockholm"), + ("Europe/Tallinn", "Europe/Tallinn"), + ("Europe/Tirane", "Europe/Tirane"), + ("Europe/Tiraspol", "Europe/Tiraspol"), + ("Europe/Ulyanovsk", "Europe/Ulyanovsk"), + ("Europe/Uzhgorod", "Europe/Uzhgorod"), + ("Europe/Vaduz", "Europe/Vaduz"), + ("Europe/Vatican", "Europe/Vatican"), + ("Europe/Vienna", "Europe/Vienna"), + ("Europe/Vilnius", "Europe/Vilnius"), + ("Europe/Volgograd", "Europe/Volgograd"), + ("Europe/Warsaw", "Europe/Warsaw"), + ("Europe/Zagreb", "Europe/Zagreb"), + ("Europe/Zaporozhye", "Europe/Zaporozhye"), + ("Europe/Zurich", "Europe/Zurich"), + ("Factory", "Factory"), + ("GB", "GB"), + ("GB-Eire", "GB-Eire"), + ("GMT", "GMT"), + ("GMT+0", "GMT+0"), + ("GMT-0", "GMT-0"), + ("GMT0", "GMT0"), + ("Greenwich", "Greenwich"), + ("HST", "HST"), + ("Hongkong", "Hongkong"), + ("Iceland", "Iceland"), + ("Indian/Antananarivo", "Indian/Antananarivo"), + ("Indian/Chagos", "Indian/Chagos"), + ("Indian/Christmas", "Indian/Christmas"), + ("Indian/Cocos", "Indian/Cocos"), + ("Indian/Comoro", "Indian/Comoro"), + ("Indian/Kerguelen", "Indian/Kerguelen"), + ("Indian/Mahe", "Indian/Mahe"), + ("Indian/Maldives", "Indian/Maldives"), + ("Indian/Mauritius", "Indian/Mauritius"), + ("Indian/Mayotte", "Indian/Mayotte"), + ("Indian/Reunion", "Indian/Reunion"), + ("Iran", "Iran"), + ("Israel", "Israel"), + ("Jamaica", "Jamaica"), + ("Japan", "Japan"), + ("Kwajalein", "Kwajalein"), + ("Libya", "Libya"), + ("MET", "MET"), + ("MST", "MST"), + ("MST7MDT", "MST7MDT"), + ("Mexico/BajaNorte", "Mexico/BajaNorte"), + ("Mexico/BajaSur", "Mexico/BajaSur"), + ("Mexico/General", "Mexico/General"), + ("NZ", "NZ"), + ("NZ-CHAT", "NZ-CHAT"), + ("Navajo", "Navajo"), + ("PRC", "PRC"), + ("PST8PDT", "PST8PDT"), + ("Pacific/Apia", "Pacific/Apia"), + ("Pacific/Auckland", "Pacific/Auckland"), + ("Pacific/Bougainville", "Pacific/Bougainville"), + ("Pacific/Chatham", "Pacific/Chatham"), + ("Pacific/Chuuk", "Pacific/Chuuk"), + ("Pacific/Easter", "Pacific/Easter"), + ("Pacific/Efate", "Pacific/Efate"), + ("Pacific/Enderbury", "Pacific/Enderbury"), + ("Pacific/Fakaofo", "Pacific/Fakaofo"), + ("Pacific/Fiji", "Pacific/Fiji"), + ("Pacific/Funafuti", "Pacific/Funafuti"), + ("Pacific/Galapagos", "Pacific/Galapagos"), + ("Pacific/Gambier", "Pacific/Gambier"), + ("Pacific/Guadalcanal", "Pacific/Guadalcanal"), + ("Pacific/Guam", "Pacific/Guam"), + ("Pacific/Honolulu", "Pacific/Honolulu"), + ("Pacific/Johnston", "Pacific/Johnston"), + ("Pacific/Kanton", "Pacific/Kanton"), + ("Pacific/Kiritimati", "Pacific/Kiritimati"), + ("Pacific/Kosrae", "Pacific/Kosrae"), + ("Pacific/Kwajalein", "Pacific/Kwajalein"), + ("Pacific/Majuro", "Pacific/Majuro"), + ("Pacific/Marquesas", "Pacific/Marquesas"), + ("Pacific/Midway", "Pacific/Midway"), + ("Pacific/Nauru", "Pacific/Nauru"), + ("Pacific/Niue", "Pacific/Niue"), + ("Pacific/Norfolk", "Pacific/Norfolk"), + ("Pacific/Noumea", "Pacific/Noumea"), + ("Pacific/Pago_Pago", "Pacific/Pago_Pago"), + ("Pacific/Palau", "Pacific/Palau"), + ("Pacific/Pitcairn", "Pacific/Pitcairn"), + ("Pacific/Pohnpei", "Pacific/Pohnpei"), + ("Pacific/Ponape", "Pacific/Ponape"), + ("Pacific/Port_Moresby", "Pacific/Port_Moresby"), + ("Pacific/Rarotonga", "Pacific/Rarotonga"), + ("Pacific/Saipan", "Pacific/Saipan"), + ("Pacific/Samoa", "Pacific/Samoa"), + ("Pacific/Tahiti", "Pacific/Tahiti"), + ("Pacific/Tarawa", "Pacific/Tarawa"), + ("Pacific/Tongatapu", "Pacific/Tongatapu"), + ("Pacific/Truk", "Pacific/Truk"), + ("Pacific/Wake", "Pacific/Wake"), + ("Pacific/Wallis", "Pacific/Wallis"), + ("Pacific/Yap", "Pacific/Yap"), + ("Poland", "Poland"), + ("Portugal", "Portugal"), + ("ROC", "ROC"), + ("ROK", "ROK"), + ("Singapore", "Singapore"), + ("Turkey", "Turkey"), + ("UCT", "UCT"), + ("US/Alaska", "US/Alaska"), + ("US/Aleutian", "US/Aleutian"), + ("US/Arizona", "US/Arizona"), + ("US/Central", "US/Central"), + ("US/East-Indiana", "US/East-Indiana"), + ("US/Eastern", "US/Eastern"), + ("US/Hawaii", "US/Hawaii"), + ("US/Indiana-Starke", "US/Indiana-Starke"), + ("US/Michigan", "US/Michigan"), + ("US/Mountain", "US/Mountain"), + ("US/Pacific", "US/Pacific"), + ("US/Samoa", "US/Samoa"), + ("UTC", "UTC"), + ("Universal", "Universal"), + ("W-SU", "W-SU"), + ("WET", "WET"), + ("Zulu", "Zulu"), + ("localtime", "localtime"), + ], + default="America/Los_Angeles", + max_length=255, + ), + ), + ] diff --git a/api/tacticalrmm/core/models.py b/api/tacticalrmm/core/models.py index e0d75faca1..8139b70063 100644 --- a/api/tacticalrmm/core/models.py +++ b/api/tacticalrmm/core/models.py @@ -3,7 +3,6 @@ from email.message import EmailMessage from typing import TYPE_CHECKING, List, Optional, cast -import pytz import requests from django.conf import settings from django.contrib.postgres.fields import ArrayField @@ -15,6 +14,7 @@ from logs.models import BaseAuditModel, DebugLog from tacticalrmm.constants import ( + ALL_TIMEZONES, CORESETTINGS_CACHE_KEY, CustomFieldModel, CustomFieldType, @@ -24,7 +24,7 @@ if TYPE_CHECKING: from alerts.models import AlertTemplate -TZ_CHOICES = [(_, _) for _ in pytz.all_timezones] +TZ_CHOICES = [(_, _) for _ in ALL_TIMEZONES] class CoreSettings(BaseAuditModel): diff --git a/api/tacticalrmm/core/serializers.py b/api/tacticalrmm/core/serializers.py index f9001146aa..09d6e407aa 100644 --- a/api/tacticalrmm/core/serializers.py +++ b/api/tacticalrmm/core/serializers.py @@ -1,6 +1,7 @@ -import pytz from rest_framework import serializers +from tacticalrmm.constants import ALL_TIMEZONES + from .models import CodeSignToken, CoreSettings, CustomField, GlobalKVStore, URLAction @@ -8,7 +9,7 @@ class CoreSettingsSerializer(serializers.ModelSerializer): all_timezones = serializers.SerializerMethodField("all_time_zones") def all_time_zones(self, obj): - return pytz.all_timezones + return ALL_TIMEZONES class Meta: model = CoreSettings diff --git a/api/tacticalrmm/core/tasks.py b/api/tacticalrmm/core/tasks.py index 6760c2114c..aaba88e01f 100644 --- a/api/tacticalrmm/core/tasks.py +++ b/api/tacticalrmm/core/tasks.py @@ -1,8 +1,12 @@ -import time +import asyncio +import logging +from contextlib import suppress from typing import TYPE_CHECKING, Any +import nats from django.conf import settings from django.db.models import Prefetch +from django.db.utils import DatabaseError from django.utils import timezone as djangotime from packaging import version as pyver @@ -30,12 +34,17 @@ PAStatus, TaskStatus, TaskSyncStatus, + TaskType, ) -from tacticalrmm.helpers import rand_range -from tacticalrmm.utils import DjangoConnectionThreadPoolExecutor, redis_lock +from tacticalrmm.helpers import setup_nats_options +from tacticalrmm.nats_utils import a_nats_cmd +from tacticalrmm.utils import redis_lock if TYPE_CHECKING: from django.db.models import QuerySet + from nats.aio.client import Client as NATSClient + +logger = logging.getLogger("trmm") @app.task @@ -148,50 +157,150 @@ def sync_scheduled_tasks(self) -> str: if not acquired: return f"{self.app.oid} still running" - task_actions = [] # list of tuples + actions: list[tuple[str, int, Agent, Any, str, str]] = [] # list of tuples + for agent in _get_agent_qs(): if ( - pyver.parse(agent.version) >= pyver.parse("1.6.0") + not agent.is_posix + and pyver.parse(agent.version) >= pyver.parse("1.6.0") and agent.status == AGENT_STATUS_ONLINE ): - # create a list of tasks to be synced so we can run them in parallel later with thread pool executor + # create a list of tasks to be synced so we can run them asynchronously for task in agent.get_tasks_with_policies(): - agent_obj = agent if task.policy else None + # TODO can we just use agent?? + agent_obj: "Agent" = agent if task.policy else task.agent + + # onboarding tasks require agent >= 2.6.0 + if task.task_type == TaskType.ONBOARDING and pyver.parse( + agent.version + ) < pyver.parse("2.6.0"): + continue # policy tasks will be an empty dict on initial if (not task.task_result) or ( isinstance(task.task_result, TaskResult) and task.task_result.sync_status == TaskSyncStatus.INITIAL ): - task_actions.append(("create", task.id, agent_obj)) + actions.append( + ( + "create", + task.id, + agent_obj, + task.generate_nats_task_payload(), + agent.agent_id, + agent.hostname, + ) + ) elif ( isinstance(task.task_result, TaskResult) and task.task_result.sync_status == TaskSyncStatus.PENDING_DELETION ): - task_actions.append(("delete", task.id, agent_obj)) + actions.append( + ( + "delete", + task.id, + agent_obj, + {}, + agent.agent_id, + agent.hostname, + ) + ) elif ( isinstance(task.task_result, TaskResult) and task.task_result.sync_status == TaskSyncStatus.NOT_SYNCED ): - task_actions.append(("modify", task.id, agent_obj)) - - def _handle_task(actions: tuple[str, int, Any]) -> None: - time.sleep(rand_range(50, 600)) - task: "AutomatedTask" = AutomatedTask.objects.get(id=actions[1]) - if actions[0] == "create": - task.create_task_on_agent(agent=actions[2]) - elif actions[0] == "modify": - task.modify_task_on_agent(agent=actions[2]) - elif actions[0] == "delete": - task.delete_task_on_agent(agent=actions[2]) - - # TODO this is a janky hack - # Rework this with asyncio. Need to rewrite all sync db operations with django's new async api - with DjangoConnectionThreadPoolExecutor(max_workers=50) as executor: - executor.map(_handle_task, task_actions) - - return "completed" + actions.append( + ( + "modify", + task.id, + agent_obj, + task.generate_nats_task_payload(), + agent.agent_id, + agent.hostname, + ) + ) + + async def _handle_task_on_agent( + nc: "NATSClient", actions: tuple[str, int, Agent, Any, str, str] + ) -> None: + # tuple: (0: action, 1: task.id, 2: agent object, 3: nats task payload, 4: agent_id, 5: agent hostname) + action = actions[0] + task_id = actions[1] + agent = actions[2] + payload = actions[3] + agent_id = actions[4] + hostname = actions[5] + + task: "AutomatedTask" = await AutomatedTask.objects.aget(id=task_id) + try: + task_result = await TaskResult.objects.aget(agent=agent, task=task) + except TaskResult.DoesNotExist: + task_result = await TaskResult.objects.acreate(agent=agent, task=task) + + if action in ("create", "modify"): + logger.debug(payload) + nats_data = { + "func": "schedtask", + "schedtaskpayload": payload, + } + + r = await a_nats_cmd(nc=nc, sub=agent_id, data=nats_data, timeout=10) + if r != "ok": + if action == "create": + task_result.sync_status = TaskSyncStatus.INITIAL + else: + task_result.sync_status = TaskSyncStatus.NOT_SYNCED + + logger.error( + f"Unable to {action} scheduled task {task.name} on {hostname}: {r}" + ) + else: + task_result.sync_status = TaskSyncStatus.SYNCED + logger.info( + f"{hostname} task {task.name} was {'created' if action == 'create' else 'modified'}" + ) + + await task_result.asave(update_fields=["sync_status"]) + # delete + else: + nats_data = { + "func": "delschedtask", + "schedtaskpayload": {"name": task.win_task_name}, + } + r = await a_nats_cmd(nc=nc, sub=agent_id, data=nats_data, timeout=10) + + if r != "ok" and "The system cannot find the file specified" not in r: + task_result.sync_status = TaskSyncStatus.PENDING_DELETION + + with suppress(DatabaseError): + await task_result.asave(update_fields=["sync_status"]) + + logger.error( + f"Unable to {action} scheduled task {task.name} on {hostname}: {r}" + ) + else: + task_name = task.name + await task.adelete() + logger.info(f"{hostname} task {task_name} was deleted.") + + async def _run(): + opts = setup_nats_options() + try: + nc = await nats.connect(**opts) + except Exception as e: + ret = str(e) + logger.error(ret) + return ret + + if tasks := [_handle_task_on_agent(nc, task) for task in actions]: + await asyncio.gather(*tasks) + + await nc.flush() + await nc.close() + + asyncio.run(_run()) + return "ok" def _get_failing_data(agents: "QuerySet[Agent]") -> dict[str, bool]: diff --git a/api/tacticalrmm/ee/reporting/migrations/0003_alter_reporthtmltemplate_name_and_more.py b/api/tacticalrmm/ee/reporting/migrations/0003_alter_reporthtmltemplate_name_and_more.py new file mode 100644 index 0000000000..a7a35fde32 --- /dev/null +++ b/api/tacticalrmm/ee/reporting/migrations/0003_alter_reporthtmltemplate_name_and_more.py @@ -0,0 +1,23 @@ +# Generated by Django 4.2.6 on 2023-11-07 18:22 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('reporting', '0002_alter_reporttemplate_type'), + ] + + operations = [ + migrations.AlterField( + model_name='reporthtmltemplate', + name='name', + field=models.CharField(max_length=200, unique=True), + ), + migrations.AlterField( + model_name='reporttemplate', + name='name', + field=models.CharField(max_length=200, unique=True), + ), + ] diff --git a/api/tacticalrmm/ee/reporting/models.py b/api/tacticalrmm/ee/reporting/models.py index f8c50f8d26..a457cf2ba7 100644 --- a/api/tacticalrmm/ee/reporting/models.py +++ b/api/tacticalrmm/ee/reporting/models.py @@ -19,7 +19,7 @@ class ReportFormatType(models.TextChoices): class ReportTemplate(models.Model): - name = models.CharField(max_length=50, unique=True) + name = models.CharField(max_length=200, unique=True) template_md = models.TextField() template_css = models.TextField(null=True, blank=True) template_html = models.ForeignKey( @@ -44,7 +44,7 @@ def __str__(self) -> str: class ReportHTMLTemplate(models.Model): - name = models.CharField(max_length=50, unique=True) + name = models.CharField(max_length=200, unique=True) html = models.TextField() def __str__(self) -> str: diff --git a/api/tacticalrmm/ee/reporting/utils.py b/api/tacticalrmm/ee/reporting/utils.py index 36449acd5a..33080c5272 100644 --- a/api/tacticalrmm/ee/reporting/utils.py +++ b/api/tacticalrmm/ee/reporting/utils.py @@ -5,6 +5,7 @@ """ import datetime +import inspect import json import re from enum import Enum @@ -20,8 +21,8 @@ from tacticalrmm.utils import get_db_value +from . import custom_filters from .constants import REPORTING_MODELS -from .custom_filters import as_tz, local_ips from .markdown.config import Markdown from .models import ReportAsset, ReportDataQuery, ReportHTMLTemplate, ReportTemplate @@ -71,13 +72,11 @@ def db_template_loader(template_name: str) -> Optional[str]: "re": re, } -custom_filters = { - "as_tz": as_tz, - "local_ips": local_ips, -} - env.globals.update(custom_globals) -env.filters.update(custom_filters) + +# import all functions from custom_filters.py +for name, func in inspect.getmembers(custom_filters, inspect.isfunction): + env.filters[name] = func def generate_pdf(*, html: str, css: str = "") -> bytes: @@ -327,45 +326,46 @@ def build_queryset(*, data_source: Dict[str, Any], limit: Optional[int] = None) queryset = queryset.first() if fields_to_add: - return add_custom_fields( + queryset = add_custom_fields( data=queryset, fields_to_add=fields_to_add, model_name=model_name, dict_value=True, ) + + if isJson: + return json.dumps(queryset, default=str) + elif isCsv: + import pandas as pd + + df = pd.DataFrame.from_dict([queryset]) + df.drop("id", axis=1, inplace=True) + if csv_columns: + df = df.rename(columns=csv_columns) + return df.to_csv(index=False) else: - if isJson: - return json.dumps(queryset, default=str) - elif isCsv: - import pandas as pd - - df = pd.DataFrame.from_dict([queryset]) - df.drop("id", axis=1, inplace=True) - if csv_columns: - df = df.rename(columns=csv_columns) - return df.to_csv(index=False) - else: - return queryset + return queryset else: # add custom fields for list results + queryset = list(queryset) + if fields_to_add: - return add_custom_fields( - data=list(queryset), fields_to_add=fields_to_add, model_name=model_name + queryset = add_custom_fields( + data=queryset, fields_to_add=fields_to_add, model_name=model_name ) + + if isJson: + return json.dumps(queryset, default=str) + elif isCsv: + import pandas as pd + + df = pd.DataFrame.from_dict(queryset) + df.drop("id", axis=1, inplace=True) + if csv_columns: + df = df.rename(columns=csv_columns) + return df.to_csv(index=False) else: - if isJson: - return json.dumps(list(queryset), default=str) - elif isCsv: - import pandas as pd - - df = pd.DataFrame.from_dict(list(queryset)) - df.drop("id", axis=1, inplace=True) - print(csv_columns) - if csv_columns: - df = df.rename(columns=csv_columns) - return df.to_csv(index=False) - else: - return list(queryset) + return queryset def add_custom_fields( diff --git a/api/tacticalrmm/requirements-dev.txt b/api/tacticalrmm/requirements-dev.txt index 5fb4307323..2c8059ece5 100644 --- a/api/tacticalrmm/requirements-dev.txt +++ b/api/tacticalrmm/requirements-dev.txt @@ -3,7 +3,6 @@ daphne==4.0.0 Werkzeug django-extensions isort -types-pytz django-silk mypy django-stubs diff --git a/api/tacticalrmm/requirements.txt b/api/tacticalrmm/requirements.txt index 8796e7209d..1059623dd1 100644 --- a/api/tacticalrmm/requirements.txt +++ b/api/tacticalrmm/requirements.txt @@ -1,15 +1,14 @@ adrf==0.1.2 asgiref==3.7.2 -celery==5.3.1 -certifi==2023.7.22 -cffi==1.15.1 +celery==5.3.5 +certifi==2023.11.17 +cffi==1.16.0 channels==4.0.0 channels_redis==4.1.0 -cryptography==41.0.5 +cryptography==41.0.7 Django==4.2.7 -django-cors-headers==4.3.0 -django-filter==23.3 -django-ipware==5.0.0 +django-cors-headers==4.3.1 +django-filter==23.4 django-rest-knox==4.2.0 djangorestframework==3.14.0 drf-spectacular==0.26.5 @@ -19,26 +18,26 @@ msgpack==1.0.7 nats-py==2.6.0 packaging==23.2 psutil==5.9.6 -psycopg[binary]==3.1.12 +psycopg[binary]==3.1.13 pycparser==2.21 pycryptodome==3.19.0 pyotp==2.9.0 pyparsing==3.1.1 -pytz==2023.3 +python-ipware==2.0.0 qrcode==7.4.2 redis==4.5.5 requests==2.31.0 six==1.16.0 sqlparse==0.4.4 -twilio==8.10.0 -urllib3==2.0.7 +twilio==8.10.2 +urllib3==2.1.0 uvicorn[standard]==0.23.2 uWSGI==2.0.22 validators==0.20.0 -vine==5.0.0 -websockets==11.0.3 +vine==5.1.0 +websockets==12.0 zipp==3.17.0 -pandas==2.1.2 +pandas==2.1.3 kaleido==0.2.1 jinja2==3.1.2 markdown==3.5.1 diff --git a/api/tacticalrmm/tacticalrmm/constants.py b/api/tacticalrmm/tacticalrmm/constants.py index 85a770130c..1ef41346e5 100644 --- a/api/tacticalrmm/tacticalrmm/constants.py +++ b/api/tacticalrmm/tacticalrmm/constants.py @@ -1,3 +1,4 @@ +import zoneinfo from enum import Enum from django.db import models @@ -74,6 +75,7 @@ class TaskType(models.TextChoices): CHECK_FAILURE = "checkfailure", "On Check Failure" MANUAL = "manual", "Manual" RUN_ONCE = "runonce", "Run Once" + ONBOARDING = "onboarding", "Onboarding" SCHEDULED = "scheduled", "Scheduled" # deprecated @@ -453,3 +455,5 @@ class DebugLogType(models.TextChoices): "certfile", "keyfile", ) + +ALL_TIMEZONES = sorted(zoneinfo.available_timezones()) diff --git a/api/tacticalrmm/tacticalrmm/middleware.py b/api/tacticalrmm/tacticalrmm/middleware.py index 63dbd97391..8f8ca3bfe1 100644 --- a/api/tacticalrmm/tacticalrmm/middleware.py +++ b/api/tacticalrmm/tacticalrmm/middleware.py @@ -3,7 +3,7 @@ from typing import Any, Dict, Optional from django.conf import settings -from ipware import get_client_ip +from python_ipware import IpWare from rest_framework.exceptions import AuthenticationFailed from tacticalrmm.constants import DEMO_NOT_ALLOWED @@ -98,9 +98,10 @@ def __init__(self, get_response): self.get_response = get_response def __call__(self, request): - client_ip, _ = get_client_ip(request) + ipw = IpWare() + client_ip, _ = ipw.get_client_ip(request.META) - request._client_ip = client_ip + request._client_ip = str(client_ip) if client_ip else "" response = self.get_response(request) return response diff --git a/api/tacticalrmm/tacticalrmm/nats_utils.py b/api/tacticalrmm/tacticalrmm/nats_utils.py index 0ccb41e463..d145857cda 100644 --- a/api/tacticalrmm/tacticalrmm/nats_utils.py +++ b/api/tacticalrmm/tacticalrmm/nats_utils.py @@ -3,6 +3,7 @@ import msgpack import nats +from nats.errors import TimeoutError as NatsTimeout from tacticalrmm.exceptions import NatsDown from tacticalrmm.helpers import setup_nats_options @@ -36,3 +37,19 @@ async def abulk_nats_command(*, items: "BULK_NATS_TASKS") -> None: await asyncio.gather(*tasks) await nc.flush() await nc.close() + + +async def a_nats_cmd( + *, nc: "NClient", sub: str, data: NATS_DATA, timeout: int = 10 +) -> str | Any: + try: + msg = await nc.request( + subject=sub, payload=msgpack.dumps(data), timeout=timeout + ) + except NatsTimeout: + return "timeout" + + try: + return msgpack.loads(msg.data) + except Exception as e: + return str(e) diff --git a/api/tacticalrmm/tacticalrmm/settings.py b/api/tacticalrmm/tacticalrmm/settings.py index e77cdcf3db..26b4fa0bfa 100644 --- a/api/tacticalrmm/tacticalrmm/settings.py +++ b/api/tacticalrmm/tacticalrmm/settings.py @@ -20,24 +20,24 @@ AUTH_USER_MODEL = "accounts.User" # latest release -TRMM_VERSION = "0.17.1" +TRMM_VERSION = "0.17.2" # https://github.com/amidaware/tacticalrmm-web -WEB_VERSION = "0.101.35" +WEB_VERSION = "0.101.37" # bump this version everytime vue code is changed # to alert user they need to manually refresh their browser -APP_VER = "0.0.187" +APP_VER = "0.0.188" # https://github.com/amidaware/rmmagent -LATEST_AGENT_VER = "2.5.0" +LATEST_AGENT_VER = "2.6.0" MESH_VER = "1.1.9" -NATS_SERVER_VER = "2.10.4" +NATS_SERVER_VER = "2.10.5" # for the update script, bump when need to recreate venv -PIP_VER = "39" +PIP_VER = "40" SETUPTOOLS_VER = "68.2.2" WHEEL_VER = "0.41.3" @@ -70,6 +70,7 @@ HOSTED = False SWAGGER_ENABLED = False REDIS_HOST = "127.0.0.1" +TRMM_LOG_LEVEL = "ERROR" with suppress(ImportError): from .local_settings import * # noqa @@ -231,12 +232,20 @@ }, ] + +def get_log_level() -> str: + if "TRMM_LOG_LEVEL" in os.environ: + return os.getenv("TRMM_LOG_LEVEL") # type: ignore + + return TRMM_LOG_LEVEL + + LOGGING = { "version": 1, "disable_existing_loggers": False, "formatters": { "verbose": { - "format": "[%(asctime)s] %(levelname)s [%(name)s:%(lineno)s] %(message)s", + "format": "[%(asctime)s] %(levelname)s [%(filename)s:%(funcName)s:%(lineno)d] %(message)s", "datefmt": "%d/%b/%Y %H:%M:%S", }, }, @@ -246,10 +255,17 @@ "class": "logging.FileHandler", "filename": os.path.join(LOG_DIR, "django_debug.log"), "formatter": "verbose", - } + }, + "trmm": { + "level": get_log_level(), + "class": "logging.FileHandler", + "filename": os.path.join(LOG_DIR, "trmm_debug.log"), + "formatter": "verbose", + }, }, "loggers": { - "django.request": {"handlers": ["file"], "level": "ERROR", "propagate": True} + "django.request": {"handlers": ["file"], "level": "ERROR", "propagate": True}, + "trmm": {"handlers": ["trmm"], "level": get_log_level(), "propagate": False}, }, } diff --git a/api/tacticalrmm/tacticalrmm/utils.py b/api/tacticalrmm/tacticalrmm/utils.py index 9ce9da0632..84d07fc2a4 100644 --- a/api/tacticalrmm/tacticalrmm/utils.py +++ b/api/tacticalrmm/tacticalrmm/utils.py @@ -3,10 +3,8 @@ import subprocess import tempfile import time -from concurrent.futures import ThreadPoolExecutor from contextlib import contextmanager -from functools import wraps -from typing import List, Optional, Union, Literal, TYPE_CHECKING +from typing import TYPE_CHECKING, List, Literal, Optional, Union from zoneinfo import ZoneInfo import requests @@ -15,7 +13,6 @@ from django.conf import settings from django.contrib.auth.models import AnonymousUser from django.core.cache import cache -from django.db import connection from django.http import FileResponse from knox.auth import TokenAuthentication from rest_framework.response import Response @@ -42,7 +39,7 @@ ) if TYPE_CHECKING: - from clients.models import Site, Client + from clients.models import Client, Site def generate_winagent_exe( @@ -429,45 +426,6 @@ def redis_lock(lock_id, oid): cache.delete(lock_id) -# https://stackoverflow.com/a/57794016 -class DjangoConnectionThreadPoolExecutor(ThreadPoolExecutor): - """ - When a function is passed into the ThreadPoolExecutor via either submit() or map(), - this will wrap the function, and make sure that close_django_db_connection() is called - inside the thread when it's finished so Django doesn't leak DB connections. - - Since map() calls submit(), only submit() needs to be overwritten. - """ - - def close_django_db_connection(self): - connection.close() - - def generate_thread_closing_wrapper(self, fn): - @wraps(fn) - def new_func(*args, **kwargs): - try: - return fn(*args, **kwargs) - finally: - self.close_django_db_connection() - - return new_func - - def submit(*args, **kwargs): - if len(args) >= 2: - self, fn, *args = args - fn = self.generate_thread_closing_wrapper(fn=fn) - elif not args: - raise TypeError( - "descriptor 'submit' of 'ThreadPoolExecutor' object " - "needs an argument" - ) - elif "fn" in kwargs: - fn = self.generate_thread_closing_wrapper(fn=kwargs.pop("fn")) - self, *args = args - - return super(self.__class__, self).submit(fn, *args, **kwargs) - - def runcmd_placeholder_text() -> dict[str, str]: ret = { "cmd": getattr( diff --git a/docker/containers/tactical-nginx/entrypoint.sh b/docker/containers/tactical-nginx/entrypoint.sh index 3340d4f7bc..bdb94565f4 100644 --- a/docker/containers/tactical-nginx/entrypoint.sh +++ b/docker/containers/tactical-nginx/entrypoint.sh @@ -27,7 +27,7 @@ else # generate a self signed cert if [ ! -f "${CERT_PRIV_PATH}" ] || [ ! -f "${CERT_PUB_PATH}" ]; then rootdomain=$(echo ${API_HOST} | cut -d "." -f2-) - openssl req -newkey rsa:4096 -x509 -sha256 -days 365 -nodes -out ${CERT_PUB_PATH} -keyout ${CERT_PRIV_PATH} -subj "/C=US/ST=Some-State/L=city/O=Internet Widgits Pty Ltd/CN=*.${rootdomain}" + openssl req -newkey rsa:4096 -x509 -sha256 -days 730 -nodes -out ${CERT_PUB_PATH} -keyout ${CERT_PRIV_PATH} -subj "/C=US/ST=Some-State/L=city/O=Internet Widgits Pty Ltd/CN=*.${rootdomain}" fi fi diff --git a/go.mod b/go.mod index 5f62be64ee..e03382d133 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/amidaware/tacticalrmm -go 1.20 +go 1.21.4 require ( github.com/jmoiron/sqlx v1.3.5 diff --git a/main.go b/main.go index a8623f8530..8334fe94f1 100644 --- a/main.go +++ b/main.go @@ -12,7 +12,7 @@ import ( ) var ( - version = "3.4.9" + version = "3.5.0" log = logrus.New() ) diff --git a/natsapi/bin/nats-api b/natsapi/bin/nats-api index ab41163fba..1b39336a36 100755 Binary files a/natsapi/bin/nats-api and b/natsapi/bin/nats-api differ diff --git a/natsapi/bin/nats-api-arm64 b/natsapi/bin/nats-api-arm64 index a576e70162..c8a9a9180c 100755 Binary files a/natsapi/bin/nats-api-arm64 and b/natsapi/bin/nats-api-arm64 differ