Skip to content

Fix negative percent_capacity_remaining in InstanceGroupSerializer#3

Open
ambient-code[bot] wants to merge 592 commits into
develfrom
debuggernaut/AAP-70636
Open

Fix negative percent_capacity_remaining in InstanceGroupSerializer#3
ambient-code[bot] wants to merge 592 commits into
develfrom
debuggernaut/AAP-70636

Conversation

@ambient-code

@ambient-code ambient-code Bot commented Jun 18, 2026

Copy link
Copy Markdown

Summary

Fixes AAP-70636: Smart Inventory consumed capacity calculation returning negative percentages.

Root Cause

InstanceGroupSerializer.get_percent_capacity_remaining() was missing an overflow guard that InstanceSerializer already has. When consumed capacity exceeds total capacity (which happens on hybrid nodes running jobs), the method returned negative percentages (e.g., -100.0) instead of capping at 0.0.

Changes

  • awx/api/serializers.py: Added overflow guard (consumed_capacity >= capacity) to InstanceGroupSerializer.get_percent_capacity_remaining(), matching the existing pattern in InstanceSerializer.
  • awx/main/tests/unit/test_capacity.py: Added TestInstanceGroupPercentCapacityRemaining test class with parametrized formula tests and an integration test.

Testing

  • tox -e linters passes (black, flake8, yamllint)
  • New unit tests cover: normal capacity, boundary (consumed == capacity), overflow (consumed > capacity), and zero capacity scenarios

Closes: AAP-70636

Assisted-by: Debuggernaut (claude-opus-4-6) [email protected]

AlanCoding and others added 30 commits September 17, 2025 10:23
Bump migrations and delete some files

Resolve remaining conflicts

Fix requirements

Flake8 fixes

Prefer devel changes for schema

Use correct versions

Remove sso connected stuff

Update to modern actions and collection fixes

Remove unwated alias

Version problems in actions

Fix more versioning problems

Update warning string

Messed it up again

Shorten exception

More removals

Remove pbr license

Remove tests deleted in devel

Remove unexpected files

Remove some content missed in the rebase

Use sleep_task from devel

Restore devel live conftest file

Add in settings that got missed

Prefer devel version of collection test

Finish repairing .github path

Remove unintended test file duplication

Undo more unintended file additions
Remove archaic monkey patches (ansible#15338)

Remove some attached methods from User model

Test user-org sublist URLs we did not test before
…on IDs. (Moved from Tower) (ansible#16096)

* resolve bug and add simple unit tests

* Update awx_collection/plugins/modules/license.py

Co-authored-by: Andrew Potozniak <[email protected]>

---------

Co-authored-by: Andrew Potozniak <[email protected]>
* Add npm cache path to fix UI building

* skip version switch
* accept empty string for dashboard and panel IDs

* update grafana tests and add new one
* Added tests for cross org sharing of credentials

* added negative testing for sharing of credentials

* added conditions and tests for roleteamslist regarding cross org credentials

* removed redundant codes

* made error message more articulated and specific
…nsible#16111)

* Rewrite the s3 upload step to fix breakage with new Ansible version

* Use commit hash for security

* Add the public read flag
Allow users to do subscription management using
Red Hat username and password.

In basic auth case, the candlepin API
at subscriptions.rhsm.redhat.com will be used instead
of console.redhat.com.

Signed-off-by: Seth Foster <[email protected]>
* Disconnect logic to fill in role parents

Get tests passing hopefully

Whatever SonarCloud

* remove role parents/children endpoints and related views

* remove duplicate get_queryset method from RoleTeamsList

---------

Co-authored-by: Peter Braun <[email protected]>
* We had race conditions with the system_administrator role being
  created just-in-time. Instead of fixing the race condition(s), dodge
  them by ensuring the role always exists
…ansible#16113)

* migrate pr ansible#16081 to new fork

* add test coverage - add clearer error messaging

* update tests to use monkeypatch
Separate out operation subsystem metrics to fix duplicate error

Remove unnecessary comments

Revert to single subsystem_metrics_* metric with labels

Format via black
* Previously, we would error out because we assumed that when we got a
  metrics payload from redis, that there was data in it and it was for
  the current host.
* Now, we do not assume that since we got a metrics payload, that is
  well formed and for the current hostname because the hostname could
  have changed and we could have not yet collected metrics for the new
  host.
* add list item to check python deps daily
* move to weekly after we gain confidence
settings.SUBSCRIPTIONS_USERNAME and
settings.SUBSCRIPTIONS_CLIENT_ID

should be mutually exclusive. This is because
the POST to api/v2/config/attach/ accepts only
a subscription_id, and infers which credentials to
use based on settings. If both are set, it is ambiguous
and can lead to unexpected 400s when attempting
to attach a license.

Signed-off-by: Seth Foster <[email protected]>
* added sonar config file and started cleaning up
* we do not place the report at the root of the repo
* limit scope to only the awx directory and its contents
* update exclusions for things in awx/ that we don't want covered
Removed 'UI' from the list of component names in the PR template.
* prometheus-client returns an additional value as of v.0.22.0

* add license, remove outdated ones, add new embedded sources

* update requirements and UPGRADE BLOCKERs in README
…sible#16093)

* Requirements POC docs from Claude Code eval

* Removed unnecessary reference.

* Excluded custom DRF configurations per @AlanCoding

* Implement review changes from @chrismeyersfsu

---------

Co-authored-by: Peter Braun <[email protected]>
Moved the AddField operation before the RunPython operations for 'rename_jts' and 'rename_projects' in migration 0200_template_name_constraint.py. This ensures the new 'org_unique' field exists before related data migrations are executed.

Fix
```
django.db.utils.ProgrammingError: column main_unifiedjobtemplate.org_unique does not exist
```

while applying migration 0200_template_name_constraint.py

when there's a job template or poject with duplicate name in the same org
* add new file to separate out the schema check so that it is no longer
  part of CI check and won't cacuse the whole workflow to fail
* remove old API schema check from ci.yml
* actually upload PR coverage reports and inject PR number if report is
  generated from a PR
* upload general report of devel on merge and make things kinda pretty
djyasin and others added 24 commits May 26, 2026 16:43
*  INCLUDE_AWX_VAR_PREFIX to USE_TOWER_VAR_PREFIX boolean toggle replace the include legacy prefix boolean with a tower-or-awx toggle USE_TOWER_VAR_PREFIX=True (default) emits only tower_ prefixed variables, false emits only awx_ (deprecated)

* Clean up dead constant and cache get_job_variable_prefixes() calls

* Revise tests to reflect new behavior

* Fix fragile fallback test to actually exercise getattr default

* Fix mock target for settings fallback test
ansible#16457)

* [AAP-57274] Fix creator permissions for models without old-style roles

NotificationTemplate has no old-style ImplicitRoleField (like admin_role)
because notification permissions were historically org-level only.
When a non-admin user creates a notification template,
give_creator_permissions tries to sync the DAB RBAC assignment back
to the old role system and hits an AttributeError.

Catch the AttributeError so the DAB RBAC assignment still succeeds.

---------

Co-authored-by: Claude Opus 4.6 <[email protected]>
…nsible#16330)

* Address even more pytest warnings, co-authored with Opus 4.6

* Upgrade pyparsing

* Attempt to update smart inventory logic

* Move smart inventory tests here

* Fix some failing dev env tests

Assisted-by: claude

* Use shared fixture for teardown

* Fix test goof

assisted-by: claude Opus 4.6
…16466)

Django allows passing update_fields=None to model.save() to mean 'update all fields'.
However, kwargs.get('update_fields', []) returns None when the key exists with a None value,
rather than the default empty list.

This caused crashes in mark_field_for_save() and other code that assumes update_fields is
a list when doing membership tests ('field' not in update_fields) or append operations.

Changed pattern from:
  update_fields = kwargs.get('update_fields', [])

To:
  update_fields = kwargs.get('update_fields') or []

This correctly handles:
- Key missing: get() returns None → or [] gives []
- Key present with None: get() returns None → or [] gives []
- Key present with list: get() returns list → or [] keeps the list

Fixed in 12 locations across 8 model files:
- awx/main/models/base.py (3 instances)
- awx/main/models/unified_jobs.py (2)
- awx/main/models/jobs.py (2)
- awx/main/models/ad_hoc_commands.py
- awx/main/models/inventory.py
- awx/main/models/notifications.py
- awx/main/models/projects.py
- awx/main/models/workflow.py

Fixes task manager crashes with:
TypeError: argument of type 'NoneType' is not iterable
…le#16468)

* Fix bash operator precedence in repo ownership check

The condition had || operators outside proper test block grouping,
which could cause the check to fail with a shell error. Wrap the
OR conditions in parentheses with explicit [[ ]] tests.

Assisted-by: Claude Haiku 4.5 <[email protected]>

* Replace reusable workflow with direct if conditions for repo ownership check

The reusable workflow with job dependencies had a timing/evaluation issue
where jobs would still execute even when should_run=false. Using direct
if conditions with github context variables (repository, ref_name) is more
reliable and ensures jobs are properly skipped on fork pushes.

Assisted-by: Claude Haiku 4.5 <[email protected]>

* Remove unused repo-owns-branch reusable workflow

No longer needed after replacing with direct if conditions.

Assisted-by: Claude Haiku 4.5 <[email protected]>
[AAP-65882] Switch to DAB Redis cache backend

Replace awx.main.cache.AWXRedisCache with the equivalent
ansible_base.lib.cache.redis_cache.DABRedisCache and remove the
now-redundant AWX driver. The DAB driver was migrated from this
exact code and provides the same fault-tolerant cache behavior.

Signed-off-by: Tomas Z <[email protected]>
…le#16464)

* added interval null rrule check and updated tests

* Added secondly to the expected errors
…visioned (ansible#16467)

Reset orphaned waiting jobs when controller node is deprovisioned

Co-authored-by: Claude Opus 4.6 (1M context) <[email protected]>
…nsible#16475)

Revert "[AAP-53283] Fix analytics API requests to respect proxy environment variables (ansible#16451)"

This reverts commit 4548094.
Fix demo credential organization in create_preload_data
…nsible#16478)

Bump kubernetes client to >=36.0.0 to fix NO_PROXY handling
Signed-off-by: Ryan Williams <[email protected]>
Co-authored-by: Claude Sonnet 4.6 (1M context) <[email protected]>
…ansible#15463)

* Move PG version check to check_db command

Move to utils, check in pre_migrate signal

* Add back in environment var skip

* Add tests for compliance

tests Assisted-By: claude
…6469)

* AAP-65883: Refactor clear_setting_cache to use DAB shared utility

Delegate cache invalidation logic to ansible_base.lib.cache.tasks.clear_cache,
passing AWX-specific dependent key resolution (settings_registry) and
post-invalidation hook (LOG_AGGREGATOR_LEVEL reconfiguration) as callbacks.

Requires: ansible/django-ansible-base AAP-65883/dab-cache-invalidation-job

Assisted-by: Claude Code / Opus 4.6 (Anthropic)

* AAP-65883: Extract helper functions to module level

Move _resolve_setting_dependents and _post_setting_invalidation out of
clear_setting_cache for better stack traces and independent testability
per review feedback (John Westcott).

Assisted-by: Claude Code / Opus 4.6 (Anthropic)
Move plugin loading to lazy-on-first-access, DB sync to dispatcher

Remove credential type and inventory plugin loading from Django's
app.ready() path. In-memory registries (ManagedCredentialType.registry
and InventorySourceOptions.injectors) are now populated lazily on first
access via LazyLoadDict, a dict subclass that calls a loader function
on the first read operation. This ensures web workers, dispatcher
workers, and management commands all get the registries populated
exactly when needed, without eager loading at startup.

The DB sync (CredentialType.setup_tower_managed_defaults) is moved to
the dispatcher's startup task, where it only needs to run once per
deployment rather than in every Django process.

Co-Authored-By: Alan Rominger <[email protected]>
Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
The aap_token parameter was added to the collection argspec and docs
in ansible#16025, but nothing consumed it after token auth was removed in
ansible#15623: modules silently ignored the token and fell back to basic
auth, breaking token authentication through the AAP gateway.

Wire it up so requests authenticate with the provided token (e.g. one
issued by the AAP gateway, which validates it and proxies to the
controller):

- Send "Authorization: Bearer <token>" in make_request when aap_token
  is set, skipping the basic-auth login probe; basic auth is unchanged
  when no token is given
- Accept the token as a string or as the dict set as a fact by the
  ansible.platform.token module ({token: ..., id: ...}), which is the
  documented cross-collection mint/use/delete workflow
- Restore controller_oauthtoken and tower_oauthtoken as aliases for
  back-compat with pre-ansible#15623 playbooks, matching downstream
- Forward aap_token through the controller_api lookup and controller
  inventory plugins via short_params, and add the missing
  CONTROLLER_OAUTH_TOKEN/TOWER_OAUTH_TOKEN env sources to the plugin
  doc fragment (plugins resolve env vars from doc fragments, not
  env_fallback); AAP_TOKEN is no longer marked deprecated there
- Support tokens in the awxkit-based export/import modules
- Add unit tests covering the Bearer header for both token forms, the
  aliases, the bad-dict failure, and the basic-auth fallback

Verified end-to-end against a live gateway-fronted AAP 2.7 deployment:
modules, the lookup plugin, both aliases, all env sources, dict-form
tokens, job launch/wait, and a clean HTTP 401 on an invalid token.

Co-Authored-By: Claude Fable 5 <[email protected]>
…nsible#16500)

* Restore oauth_token backward compatibility for collection token auth

The aap_token rename (c8981e3) restored module-level token auth but
left two interfaces from earlier collection releases broken:

- The lookup (controller_api) and inventory (controller) plugins
  previously declared an oauth_token option. Add oauth_token as an
  alias of aap_token in the auth_plugin doc fragment and in
  AUTH_ARGSPEC so query(..., oauth_token=...) and inventory YAML keys
  keep working.

- tower_cli.cfg-style config files used an oauth_token key under
  [general]; it was silently ignored after the rename, quietly
  degrading auth. load_config() now also reads the legacy oauth_token
  key and maps it to aap_token, with the new aap_token key winning when
  both are present. aap_token remains the canonical attribute used by
  _parse_aap_token() and the Bearer header logic.

Also make the test helper compatible with ansible-core 2.21+, which
requires a serialization profile alongside _ANSIBLE_ARGS, and extend
the tests to cover the oauth_token alias and legacy config file key.

No changelog fragment added: awx_collection has no changelogs/
directory on devel.

Co-Authored-By: Claude Opus 4.8 <[email protected]>

* Document oauth_token alias in module auth doc fragment

The oauth_token alias was added to aap_token in AUTH_ARGSPEC but not to
the module doc fragment, failing the validate-modules sanity check
(undocumented argument alias).

Co-Authored-By: Claude Opus 4.8 <[email protected]>

* Generalize version references in compat comments

Co-Authored-By: Claude Opus 4.8 <[email protected]>

---------

Co-authored-by: Claude Opus 4.8 <[email protected]>
fix: resolve SonarCloud security rating C (AAP-79142)

Replace regex-based substring checks with plain `in` operator in awxkit
page.py to eliminate ReDoS vulnerability (python:S5852). Remove stray
empty Pipfile that triggered missing lockfile warning (text:S8565).

Co-authored-by: Claude Opus 4.6 (1M context) <[email protected]>
feat: inject x-ai-description from overlay file during schema generation

Many endpoints have human-readable AI descriptions that were added
downstream in aap-mcp-server (PRs ansible#73 and ansible#119) but never backported
as @extend_schema_if_available decorators. This causes 470 out of 631
x-ai-description entries to be lost every time the spec is regenerated.

Add a JSON overlay file (openapi_ai_descriptions.json) containing the
missing descriptions keyed by operationId, and a drf-spectacular
postprocessing hook that merges them into the generated schema for any
operation that doesn't already have x-ai-description from a decorator.

Co-authored-by: Claude Opus 4.6 (1M context) <[email protected]>
…#16509)

The aap-openapi-specs repo requires commit signatures via org ruleset.
Switch from git commit+push to the GitHub Git Data API which
automatically signs commits, satisfying the required_signatures rule.

Co-authored-by: Claude Opus 4.6 (1M context) <[email protected]>
…rcent_capacity_remaining

When consumed capacity exceeds total capacity on hybrid nodes, the
InstanceGroupSerializer.get_percent_capacity_remaining method returned
negative percentages instead of capping at 0.0. This adds the same
overflow guard that already exists in InstanceSerializer.

Debuggernaut autonomous fix. See PR description for full analysis.

Assisted-by: Debuggernaut (claude-opus-4-6) <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.