├── __init__.py
├── Squest
├── __init__.py
├── api
│ ├── __init__.py
│ ├── celery_tasks_views.py
│ └── authentication.py
├── utils
│ ├── __init__.py
│ ├── squest_encoder.py
│ ├── squest_table.py
│ └── ansible_when.py
├── middleware
│ └── __init__.py
├── models
│ ├── __init__.py
│ └── singleton_model.py
├── version.py
├── wsgi.py
└── asgi.py
├── tests
├── __init__.py
├── test_plugins
│ ├── __init__.py
│ ├── field_validators_test
│ │ ├── __init__.py
│ │ ├── superior_to_10.py
│ │ └── even_number.py
│ ├── survey_validators_test
│ │ └── __init__.py
│ └── test_provided_validators
│ │ └── __init__.py
├── test_profiles
│ ├── __init__.py
│ ├── base
│ │ └── __init__.py
│ ├── test_api
│ │ ├── __init__.py
│ │ ├── test_urls
│ │ │ ├── __init__.py
│ │ │ └── test_quota
│ │ │ │ └── __init__.py
│ │ ├── test_user
│ │ │ └── __init__.py
│ │ └── test_notification_filter
│ │ │ ├── __init__.py
│ │ │ ├── test_instance_notification
│ │ │ └── __init__.py
│ │ │ └── test_request_notification
│ │ │ └── __init__.py
│ ├── test_forms
│ │ ├── __init__.py
│ │ └── test_notification_filter_form.py
│ ├── test_model
│ │ └── __init__.py
│ ├── test_urls
│ │ ├── __init__.py
│ │ └── test_user.py
│ ├── test_views
│ │ └── __init__.py
│ └── test_notification_filters
│ │ └── __init__.py
├── test_service_catalog
│ ├── __init__.py
│ ├── test_api
│ │ ├── __init__.py
│ │ ├── test_urls
│ │ │ ├── __init__.py
│ │ │ ├── test_instance
│ │ │ │ └── __init__.py
│ │ │ ├── test_request
│ │ │ │ ├── __init__.py
│ │ │ │ └── test_state_machine
│ │ │ │ │ └── __init__.py
│ │ │ └── test_approvalworkflow
│ │ │ │ └── __init__.py
│ │ ├── test_views
│ │ │ ├── __init__.py
│ │ │ └── test_approvalworkflow
│ │ │ │ └── __init__.py
│ │ ├── test_instance
│ │ │ ├── __init__.py
│ │ │ ├── test_spec
│ │ │ │ └── __init__.py
│ │ │ └── test_user_spec
│ │ │ │ ├── __init__.py
│ │ │ │ ├── test_user_spec_put.py
│ │ │ │ └── test_user_spec_patch.py
│ │ ├── test_operation
│ │ │ ├── __init__.py
│ │ │ └── test_survey
│ │ │ │ └── __init__.py
│ │ ├── test_portfolio
│ │ │ └── __init__.py
│ │ ├── test_request
│ │ │ ├── __init__.py
│ │ │ └── test_request_state_machine
│ │ │ │ └── __init__.py
│ │ ├── test_service
│ │ │ └── __init__.py
│ │ ├── test_custom_link
│ │ │ └── __init__.py
│ │ ├── test_serializers
│ │ │ └── __init__.py
│ │ └── test_tower_server
│ │ │ ├── __init__.py
│ │ │ └── test_job_template
│ │ │ └── __init__.py
│ ├── test_urls
│ │ ├── __init__.py
│ │ ├── test_instance
│ │ │ └── __init__.py
│ │ ├── test_request
│ │ │ ├── __init__.py
│ │ │ └── test_state_machine
│ │ │ │ └── __init__.py
│ │ └── test_doc.py
│ ├── test_filters
│ │ └── __init__.py
│ ├── test_forms
│ │ └── __init__.py
│ ├── test_models
│ │ ├── __init__.py
│ │ ├── test_doc.py
│ │ └── test_service.py
│ ├── test_views
│ │ ├── __init__.py
│ │ ├── test_admin
│ │ │ ├── __init__.py
│ │ │ ├── test_request
│ │ │ │ └── __init__.py
│ │ │ ├── test_support
│ │ │ │ └── __init__.py
│ │ │ ├── test_tools
│ │ │ │ ├── __init__.py
│ │ │ │ ├── test_tower
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ └── base_test_tower.py
│ │ │ │ ├── test_catalog
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── test_services
│ │ │ │ │ │ ├── __init__.py
│ │ │ │ │ │ └── test_list.py
│ │ │ │ │ ├── test_operations
│ │ │ │ │ │ ├── __init__.py
│ │ │ │ │ │ └── test_list.py
│ │ │ │ │ └── test_portfolio
│ │ │ │ │ │ └── __init__.py
│ │ │ │ ├── test_custom_links
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── test_list.py
│ │ │ │ │ └── base_test_custom_link.py
│ │ │ │ ├── test_instance_hook
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ └── test_list.py
│ │ │ │ └── test_request_hook
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ └── test_list.py
│ │ │ ├── test_announcement
│ │ │ │ └── __init__.py
│ │ │ ├── test_approval
│ │ │ │ └── __init__.py
│ │ │ └── test_instance
│ │ │ │ └── __init__.py
│ │ ├── test_common
│ │ │ └── __init__.py
│ │ └── test_customer
│ │ │ ├── __init__.py
│ │ │ ├── test_catalog
│ │ │ └── __init__.py
│ │ │ ├── test_instance
│ │ │ ├── __init__.py
│ │ │ └── test_instance_details.py
│ │ │ └── test_request
│ │ │ └── __init__.py
│ ├── test_serializers
│ │ └── __init__.py
│ └── test_template_tags
│ │ └── __init__.py
├── test_resource_tracker_v2
│ ├── __init__.py
│ ├── test_api
│ │ ├── __init__.py
│ │ ├── test_urls
│ │ │ └── __init__.py
│ │ └── test_serializers
│ │ │ └── __init__.py
│ ├── test_forms
│ │ └── __init__.py
│ ├── test_model
│ │ ├── __init__.py
│ │ └── test_attribute_definition.py
│ ├── test_urls
│ │ └── __init__.py
│ └── test_views
│ │ └── __init__.py
├── setup
│ ├── __init__.py
│ ├── setup_org.py
│ ├── setup_team.py
│ └── setup_service.py
└── test_swagger_view.py
├── monitoring
├── __init__.py
├── migrations
│ └── __init__.py
├── admin.py
├── urls.py
└── apps.py
├── plugins
├── __init__.py
├── field_validators
│ ├── __init__.py
│ └── is_json.py
└── survey_validators
│ └── __init__.py
├── profiles
├── __init__.py
├── api
│ ├── __init__.py
│ ├── serializers
│ │ ├── team_serializer.py
│ │ ├── role_serializer.py
│ │ ├── contenttype_serializer.py
│ │ ├── permission_serializers.py
│ │ ├── globalscope_serializer.py
│ │ ├── rbac_serializers.py
│ │ ├── organization_serializer.py
│ │ └── __init__.py
│ └── views
│ │ ├── __init__.py
│ │ ├── role_api_views.py
│ │ ├── team_api_views.py
│ │ ├── globalscope_api_views.py
│ │ ├── user_api_views.py
│ │ ├── permission_api_views.py
│ │ └── organization_api_views.py
├── default_rbac
│ └── __init__.py
├── migrations
│ ├── __init__.py
│ ├── 0013_delete_billinggroup.py
│ ├── 0015_profile_theme.py
│ ├── 0022_alter_permission_options.py
│ ├── 0019_alter_quota_options.py
│ ├── 0007_auto_20221005_1107.py
│ └── 0002_auto_20211105_0946.py
├── templatetags
│ └── __init__.py
├── admin.py
├── filters
│ ├── __init__.py
│ ├── role_filter.py
│ ├── team_filter.py
│ ├── organization_filter.py
│ ├── notification_filter_filter.py
│ ├── quota.py
│ ├── permission_filter.py
│ └── user_filter.py
├── forms
│ ├── __init__.py
│ ├── role_forms.py
│ ├── team_forms.py
│ ├── organization_forms.py
│ ├── globalscope_forms.py
│ ├── permission_form.py
│ ├── token_forms.py
│ ├── model_permission_form.py
│ └── scope_form.py
├── tables
│ ├── __init__.py
│ ├── team_quota_limit_table.py
│ ├── instance_consumption_table.py
│ ├── permission_table.py
│ ├── approval_workflow.py
│ └── notification_filter_table.py
├── views
│ └── __init__.py
└── models
│ ├── rbac.py
│ ├── __init__.py
│ ├── notification_filter.py
│ └── squest_permission.py
├── scripts
└── __init__.py
├── resource_tracker_v2
├── __init__.py
├── api
│ ├── __init__.py
│ ├── views
│ │ ├── __init__.py
│ │ ├── resource_api_view.py
│ │ ├── transformer_api_views.py
│ │ ├── resource_group_api_views.py
│ │ └── attribute_definition_api_views.py
│ └── serializers
│ │ ├── __init__.py
│ │ ├── attribute_definition_serializers.py
│ │ └── resource_group_serializers.py
├── forms
│ ├── __init__.py
│ ├── resource_group_form.py
│ └── attribute_definition_form.py
├── tables
│ ├── __init__.py
│ ├── attribute_defintion_table.py
│ └── transformer_table.py
├── filters
│ ├── __init__.py
│ ├── resource_group_filter.py
│ ├── attribute_definition_filter.py
│ ├── resource_filter.py
│ └── transformer_filter.py
├── management
│ ├── __init__.py
│ └── commands
│ │ └── __init__.py
├── migrations
│ ├── __init__.py
│ └── 0004_alter_transformer_factor.py
├── views
│ ├── utils
│ │ └── __init__.py
│ └── __init__.py
├── templatetags
│ ├── __init__.py
│ └── resource_filters.py
├── tests.py
├── admin.py
├── apps.py
└── models
│ ├── __init__.py
│ ├── resource_group.py
│ └── resource_attribute.py
├── service_catalog
├── api
│ ├── __init__.py
│ ├── serializers
│ │ ├── task_result_serializer.py
│ │ ├── job_template_serializer.py
│ │ ├── custom_link_serializer.py
│ │ ├── portfolio_serializer.py
│ │ ├── __init__.py
│ │ ├── service_serializers.py
│ │ ├── operation_serializers.py
│ │ ├── request_message_serializer.py
│ │ ├── tower_server_serializer.py
│ │ ├── approval_step_state_serializer.py
│ │ └── approval_workflow_state_serializer.py
│ └── views
│ │ ├── job_template_api_views.py
│ │ ├── portfolio_api_views.py
│ │ ├── custom_link_api_views.py
│ │ ├── approval_step_api_views.py
│ │ ├── __init__.py
│ │ └── tower_server_api_views.py
├── filters
│ ├── __init__.py
│ ├── approval_step_filter.py
│ ├── service_filter.py
│ ├── tower_server_filter.py
│ ├── portfolio_filter.py
│ ├── job_template_filter.py
│ ├── approval_workflow_filter.py
│ ├── email_template_filter.py
│ ├── global_hook_filter.py
│ ├── doc_filter.py
│ ├── operation_filter.py
│ ├── custom_link_filter.py
│ └── support_filter.py
├── management
│ ├── __init__.py
│ └── commands
│ │ ├── __init__.py
│ │ └── martor_cleanup.py
├── migrations
│ ├── __init__.py
│ ├── 0045_alter_doc_options.py
│ ├── 0046_alter_doc_options.py
│ ├── 0007_service_external_support_url.py
│ ├── 0033_alter_approvalstepstate_options_and_more.py
│ ├── 0020_alter_approvalstep_options.py
│ ├── 0010_doc_operations.py
│ ├── 0021_approvalstep_auto_accept_condition.py
│ ├── 0025_alter_approvalstep_auto_accept_condition.py
│ ├── 0043_operation_when.py
│ ├── 0034_alter_request_approval_workflow_state.py
│ ├── 0031_service_attribute_definitions.py
│ ├── 0029_alter_instance_requester.py
│ ├── 0032_alter_operation_name_alter_operation_type.py
│ ├── 0036_approvalworkflow_enabled.py
│ ├── 0041_operation_validators.py
│ ├── 0038_alter_towersurveyfield_unique_together_and_more.py
│ ├── 0016_alter_request_options.py
│ ├── 0027_alter_approvalworkflow_scopes.py
│ ├── 0028_set_last_update_on_request.py
│ ├── 0035_alter_request_options.py
│ └── 0022_auto_20230906_1539.py
├── tables
│ ├── __init__.py
│ ├── doc_tables.py
│ ├── portfolio_tables.py
│ ├── email_template_table.py
│ ├── custom_link_table.py
│ ├── support_tables.py
│ ├── annoucement_tables.py
│ ├── service_tables.py
│ └── tower_server_tables.py
├── templatetags
│ ├── __init__.py
│ ├── maintenance.py
│ └── version.py
├── __init__.py
├── models
│ ├── approval_state.py
│ ├── exceptions.py
│ ├── operation_type.py
│ ├── bootstrap_type.py
│ ├── squest_settings.py
│ ├── request_state.py
│ ├── instance_state.py
│ ├── inventory.py
│ └── credential.py
├── forms
│ ├── request_forms.py
│ ├── custom_link_form.py
│ ├── doc_forms.py
│ ├── __init__.py
│ ├── global_hook_forms.py
│ ├── tower_server_update_token_forms.py
│ └── request_message_forms.py
├── celery.py
├── views
│ ├── login.py
│ ├── __init__.py
│ └── custom_link.py
└── admin.py
├── docker
├── gitconfig
├── environment_variables
│ ├── redis.env
│ ├── phpmyadmin.env
│ ├── rabbitmq.env
│ └── db.env
├── scripts
│ ├── mariadb-init.sh
│ └── psql-init.sh
├── maintenance.nginx.conf
├── entrypoint.sh
└── Caddyfile
├── templates
├── 403_csrf.html
├── generics
│ ├── custom_columns
│ │ ├── generic_boolean.html
│ │ ├── generic_date_format.html
│ │ ├── generic_actions.html
│ │ └── generic_boolean_check.html
│ ├── ajax-option.html
│ ├── buttons
│ │ ├── bulk_delete_button.html
│ │ ├── add_button.html
│ │ ├── edit_button.html
│ │ └── delete_button.html
│ ├── table
│ │ └── table.html
│ ├── generic_form.html
│ └── breadcrumbs.html
├── service_catalog
│ ├── custom_columns
│ │ ├── tower_server_host.html
│ │ ├── operation_type.html
│ │ ├── support_state.html
│ │ ├── preview_workflow.html
│ │ ├── service_operations.html
│ │ ├── tower_server_job_templates.html
│ │ ├── service_actions.html
│ │ ├── create_operation_request.html
│ │ ├── global_hook_state.html
│ │ ├── job_template_compliant.html
│ │ ├── operation_request.html
│ │ ├── tower_server_actions.html
│ │ └── job_template_actions.html
│ ├── buttons
│ │ ├── instance-archived-list.html
│ │ ├── request-archived-list.html
│ │ ├── reject_button.html
│ │ ├── tower_server_new_token.html
│ │ ├── manage_docs.html
│ │ ├── operation_survey_button.html
│ │ ├── delete_operation_button.html
│ │ ├── edit_operation_button.html
│ │ ├── instance_edit_button.html
│ │ └── request_state_machine.html
│ ├── admin
│ │ └── service
│ │ │ └── operation
│ │ │ └── operation-button-edit-survey.html
│ └── mails
│ │ └── utils
│ │ └── header.html
├── resource_tracker_v2
│ └── resource_group
│ │ ├── custom_columns
│ │ ├── attribute_value.html
│ │ ├── tags.html
│ │ ├── resource_group_resource.html
│ │ ├── resource_group_attributes_button.html
│ │ └── resource_group_attribute_actions.html
│ │ ├── button_switch_table.html
│ │ ├── button_switch_csv.html
│ │ └── resources
│ │ ├── resource-delete-button.html
│ │ ├── resource-edit-button.html
│ │ ├── resource-move-button.html
│ │ ├── custom_columns
│ │ └── resource_operations.html
│ │ └── resource_list_buttons.html
├── profiles
│ ├── custom_columns
│ │ ├── preview_workflow.html
│ │ ├── delete_all_user_roles.html
│ │ └── user_roles.html
│ ├── buttons
│ │ └── manage_all_users.html
│ └── forms
│ │ └── form_headers
│ │ ├── instance_notification_filter_header.html
│ │ └── request_notification_filter_header.html
├── 404.html
├── 500.html
└── 403.html
├── k8s
├── requirements.txt
├── requirements.yml
├── squest_k8s
│ ├── defaults
│ │ └── main.yml
│ ├── templates
│ │ ├── common
│ │ │ └── labels.yml
│ │ └── squest_secrets.yaml
│ └── tasks
│ │ ├── 06-celery.yml
│ │ ├── 03-redis.yml
│ │ └── 02-rabbitmq.yml
├── .ansible-lint
└── deploy.yml
├── docs
├── images
│ ├── squest_logo_v2.png
│ ├── rbac.png
│ ├── quota.png
│ ├── vm_rg.png
│ ├── attribute.png
│ ├── cluster_rg.png
│ ├── k8s_example.png
│ ├── permissions.png
│ ├── survey_quota.png
│ ├── approval_workflow.png
│ ├── squest_full_logo.png
│ ├── squest_logo_white.png
│ └── grafana_panel_example.png
└── index.md
├── playbook_examples
├── squest_inventory
│ ├── inventory
│ ├── squest_extra_vars
│ │ ├── delete.yml
│ │ ├── update.yml
│ │ └── create.yml
│ ├── group_vars
│ │ └── squest_testing.yml
│ └── README.md
├── test_get_api.yml
└── file_service_example
│ └── delete.yml
├── .dockerignore
├── project-static
└── squest
│ ├── img
│ ├── admin.png
│ ├── user.png
│ ├── no_image.png
│ ├── squest_logo.png
│ ├── squest_logo_v2_100_100.png
│ ├── squest_logo_v2_300_300.png
│ ├── squest_logo_v2_600_600.png
│ ├── squest_logo_v2_1417_1417.png
│ └── squest_full_logo_transparent.v1.png
│ ├── js
│ ├── dashboards.js
│ └── resource_group_attributes.js
│ └── css
│ └── squest-dark.css
├── default_data.yml
├── .coveragerc
├── docker-compose.override.yml
├── .github
└── ISSUE_TEMPLATE
│ ├── miscellaneous.md
│ ├── feature_request.md
│ └── bug_report.md
├── package.json
├── dev.docker-compose.yml
├── tls.docker-compose.yml
├── psql.docker-compose.yaml
├── ldap.docker-compose.yml
└── manage.py
/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/Squest/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/tests/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/Squest/api/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/monitoring/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/plugins/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/profiles/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/scripts/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/Squest/utils/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/profiles/api/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/Squest/middleware/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/Squest/models/__init__.py:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/monitoring/migrations/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/profiles/default_rbac/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/profiles/migrations/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/profiles/templatetags/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/resource_tracker_v2/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/service_catalog/api/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/tests/test_plugins/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/tests/test_profiles/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/plugins/field_validators/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/plugins/survey_validators/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/resource_tracker_v2/api/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/resource_tracker_v2/forms/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/resource_tracker_v2/tables/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/service_catalog/filters/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/service_catalog/management/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/service_catalog/migrations/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/service_catalog/tables/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/tests/test_profiles/base/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/tests/test_service_catalog/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/resource_tracker_v2/api/views/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/resource_tracker_v2/filters/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/resource_tracker_v2/management/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/resource_tracker_v2/migrations/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/resource_tracker_v2/views/utils/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/service_catalog/templatetags/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/tests/test_profiles/test_api/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/tests/test_profiles/test_forms/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/tests/test_profiles/test_model/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/tests/test_profiles/test_urls/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/tests/test_profiles/test_views/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/tests/test_resource_tracker_v2/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/resource_tracker_v2/api/serializers/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/resource_tracker_v2/templatetags/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/service_catalog/management/commands/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/tests/test_service_catalog/test_api/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/tests/test_service_catalog/test_urls/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/docker/gitconfig:
--------------------------------------------------------------------------------
1 | [safe]
2 | directory = /app
3 |
--------------------------------------------------------------------------------
/profiles/admin.py:
--------------------------------------------------------------------------------
1 | # Register your models here.
2 |
--------------------------------------------------------------------------------
/resource_tracker_v2/management/commands/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/templates/403_csrf.html:
--------------------------------------------------------------------------------
1 | {% include "403.html" %}
2 |
--------------------------------------------------------------------------------
/tests/test_plugins/field_validators_test/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/tests/test_plugins/survey_validators_test/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/tests/test_profiles/test_api/test_urls/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/tests/test_profiles/test_api/test_user/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/tests/test_resource_tracker_v2/test_api/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/tests/test_resource_tracker_v2/test_forms/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/tests/test_resource_tracker_v2/test_model/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/tests/test_resource_tracker_v2/test_urls/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/tests/test_resource_tracker_v2/test_views/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/tests/test_service_catalog/test_filters/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/tests/test_service_catalog/test_forms/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/tests/test_service_catalog/test_models/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/tests/test_service_catalog/test_views/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/resource_tracker_v2/tests.py:
--------------------------------------------------------------------------------
1 | # Create your tests here.
2 |
--------------------------------------------------------------------------------
/tests/test_plugins/test_provided_validators/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/tests/test_profiles/test_notification_filters/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/tests/test_service_catalog/test_api/test_urls/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/tests/test_service_catalog/test_api/test_views/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/tests/test_service_catalog/test_serializers/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/tests/test_service_catalog/test_template_tags/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/k8s/requirements.txt:
--------------------------------------------------------------------------------
1 | kubernetes==24.2.0
2 | ansible==11.6.0
3 |
--------------------------------------------------------------------------------
/resource_tracker_v2/admin.py:
--------------------------------------------------------------------------------
1 | # Register your models here.
2 |
--------------------------------------------------------------------------------
/tests/test_profiles/test_api/test_urls/test_quota/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/tests/test_resource_tracker_v2/test_api/test_urls/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/tests/test_service_catalog/test_api/test_instance/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/tests/test_service_catalog/test_api/test_operation/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/tests/test_service_catalog/test_api/test_portfolio/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/tests/test_service_catalog/test_api/test_request/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/tests/test_service_catalog/test_api/test_service/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/tests/test_service_catalog/test_urls/test_instance/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/tests/test_service_catalog/test_urls/test_request/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/tests/test_service_catalog/test_views/test_admin/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/tests/test_service_catalog/test_views/test_common/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/tests/test_service_catalog/test_views/test_customer/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/tests/test_profiles/test_api/test_notification_filter/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/tests/test_resource_tracker_v2/test_api/test_serializers/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/tests/test_service_catalog/test_api/test_custom_link/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/tests/test_service_catalog/test_api/test_serializers/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/tests/test_service_catalog/test_api/test_tower_server/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/Squest/version.py:
--------------------------------------------------------------------------------
1 | __version__ = "2.8.1"
2 | VERSION = __version__
3 |
--------------------------------------------------------------------------------
/tests/test_service_catalog/test_api/test_instance/test_spec/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/tests/test_service_catalog/test_api/test_urls/test_instance/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/tests/test_service_catalog/test_api/test_urls/test_request/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/tests/test_service_catalog/test_views/test_admin/test_request/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/tests/test_service_catalog/test_views/test_admin/test_support/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/tests/test_service_catalog/test_views/test_admin/test_tools/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/tests/test_service_catalog/test_api/test_instance/test_user_spec/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/tests/test_service_catalog/test_api/test_operation/test_survey/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/tests/test_service_catalog/test_views/test_admin/test_announcement/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/tests/test_service_catalog/test_views/test_admin/test_approval/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/tests/test_service_catalog/test_views/test_admin/test_instance/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/tests/test_service_catalog/test_views/test_customer/test_catalog/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/tests/test_service_catalog/test_views/test_customer/test_instance/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/tests/test_service_catalog/test_views/test_customer/test_request/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/tests/test_service_catalog/test_api/test_tower_server/test_job_template/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/tests/test_service_catalog/test_api/test_urls/test_approvalworkflow/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/tests/test_service_catalog/test_api/test_views/test_approvalworkflow/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/tests/test_service_catalog/test_urls/test_request/test_state_machine/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/tests/test_service_catalog/test_views/test_admin/test_tools/test_tower/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/docs/images/squest_logo_v2.png:
--------------------------------------------------------------------------------
1 | ../../project-static/squest/img/squest_logo_v2_300_300.png
--------------------------------------------------------------------------------
/templates/generics/custom_columns/generic_boolean.html:
--------------------------------------------------------------------------------
1 | {{ value | display_boolean }}
2 |
--------------------------------------------------------------------------------
/tests/test_service_catalog/test_api/test_request/test_request_state_machine/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/tests/test_service_catalog/test_views/test_admin/test_tools/test_catalog/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/k8s/requirements.yml:
--------------------------------------------------------------------------------
1 | collections:
2 | - name: kubernetes.core
3 | version: 5.2.0
4 |
--------------------------------------------------------------------------------
/tests/test_profiles/test_api/test_notification_filter/test_instance_notification/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/tests/test_profiles/test_api/test_notification_filter/test_request_notification/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/tests/test_service_catalog/test_api/test_urls/test_request/test_state_machine/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/tests/test_service_catalog/test_views/test_admin/test_tools/test_custom_links/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/tests/test_service_catalog/test_views/test_admin/test_tools/test_instance_hook/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/tests/test_service_catalog/test_views/test_admin/test_tools/test_request_hook/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/docs/images/rbac.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HewlettPackard/squest/HEAD/docs/images/rbac.png
--------------------------------------------------------------------------------
/monitoring/admin.py:
--------------------------------------------------------------------------------
1 | from django.contrib import admin
2 |
3 | # Register your models here.
4 |
--------------------------------------------------------------------------------
/templates/generics/custom_columns/generic_date_format.html:
--------------------------------------------------------------------------------
1 | {{ value | squest_date_format }}
2 |
--------------------------------------------------------------------------------
/tests/test_service_catalog/test_views/test_admin/test_tools/test_catalog/test_services/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/docker/environment_variables/redis.env:
--------------------------------------------------------------------------------
1 | TZ=Europe/Paris
2 | REDIS_PASSWORD=redis_secret_password
3 |
--------------------------------------------------------------------------------
/docs/images/quota.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HewlettPackard/squest/HEAD/docs/images/quota.png
--------------------------------------------------------------------------------
/docs/images/vm_rg.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HewlettPackard/squest/HEAD/docs/images/vm_rg.png
--------------------------------------------------------------------------------
/playbook_examples/squest_inventory/inventory:
--------------------------------------------------------------------------------
1 | [squest_testing]
2 | localhost ansible_connection=local
--------------------------------------------------------------------------------
/tests/test_service_catalog/test_views/test_admin/test_tools/test_catalog/test_operations/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/tests/test_service_catalog/test_views/test_admin/test_tools/test_catalog/test_portfolio/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/docs/images/attribute.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HewlettPackard/squest/HEAD/docs/images/attribute.png
--------------------------------------------------------------------------------
/.dockerignore:
--------------------------------------------------------------------------------
1 | /static
2 | /node_modules
3 | /media
4 | /docker/certs/*
5 | /backup
6 | /site
7 | /htmlcov
8 |
--------------------------------------------------------------------------------
/docs/images/cluster_rg.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HewlettPackard/squest/HEAD/docs/images/cluster_rg.png
--------------------------------------------------------------------------------
/docs/images/k8s_example.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HewlettPackard/squest/HEAD/docs/images/k8s_example.png
--------------------------------------------------------------------------------
/docs/images/permissions.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HewlettPackard/squest/HEAD/docs/images/permissions.png
--------------------------------------------------------------------------------
/docs/images/survey_quota.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HewlettPackard/squest/HEAD/docs/images/survey_quota.png
--------------------------------------------------------------------------------
/templates/service_catalog/custom_columns/tower_server_host.html:
--------------------------------------------------------------------------------
1 | {{ record.url }}
--------------------------------------------------------------------------------
/docs/images/approval_workflow.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HewlettPackard/squest/HEAD/docs/images/approval_workflow.png
--------------------------------------------------------------------------------
/docs/images/squest_full_logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HewlettPackard/squest/HEAD/docs/images/squest_full_logo.png
--------------------------------------------------------------------------------
/docs/images/squest_logo_white.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HewlettPackard/squest/HEAD/docs/images/squest_logo_white.png
--------------------------------------------------------------------------------
/project-static/squest/img/admin.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HewlettPackard/squest/HEAD/project-static/squest/img/admin.png
--------------------------------------------------------------------------------
/project-static/squest/img/user.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HewlettPackard/squest/HEAD/project-static/squest/img/user.png
--------------------------------------------------------------------------------
/default_data.yml:
--------------------------------------------------------------------------------
1 | users:
2 | - username: admin
3 | email: admin@squest.domain
4 | password: admin
5 | is_admin: true
6 |
--------------------------------------------------------------------------------
/docs/images/grafana_panel_example.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HewlettPackard/squest/HEAD/docs/images/grafana_panel_example.png
--------------------------------------------------------------------------------
/project-static/squest/img/no_image.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HewlettPackard/squest/HEAD/project-static/squest/img/no_image.png
--------------------------------------------------------------------------------
/project-static/squest/img/squest_logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HewlettPackard/squest/HEAD/project-static/squest/img/squest_logo.png
--------------------------------------------------------------------------------
/templates/resource_tracker_v2/resource_group/custom_columns/attribute_value.html:
--------------------------------------------------------------------------------
1 | {{ record | v2_get_attribute_value_from_name:attribute_name }}
2 |
--------------------------------------------------------------------------------
/templates/service_catalog/custom_columns/operation_type.html:
--------------------------------------------------------------------------------
1 | {{ record.type }}
--------------------------------------------------------------------------------
/.coveragerc:
--------------------------------------------------------------------------------
1 | [run]
2 |
3 | omit =
4 | tests/*
5 | Squest/*
6 | manage.py
7 | */apps.py
8 | service_catalog/management/commands/*
9 |
--------------------------------------------------------------------------------
/docker/environment_variables/phpmyadmin.env:
--------------------------------------------------------------------------------
1 | TZ=Europe/Paris
2 | PMA_HOST=db
3 | PMA_ARBITRARY=1
4 | MYSQL_USERNAME=root
5 | MYSQL_ROOT_PASSWORD=p@ssw0rd
6 |
--------------------------------------------------------------------------------
/project-static/squest/img/squest_logo_v2_100_100.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HewlettPackard/squest/HEAD/project-static/squest/img/squest_logo_v2_100_100.png
--------------------------------------------------------------------------------
/project-static/squest/img/squest_logo_v2_300_300.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HewlettPackard/squest/HEAD/project-static/squest/img/squest_logo_v2_300_300.png
--------------------------------------------------------------------------------
/project-static/squest/img/squest_logo_v2_600_600.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HewlettPackard/squest/HEAD/project-static/squest/img/squest_logo_v2_600_600.png
--------------------------------------------------------------------------------
/templates/service_catalog/custom_columns/support_state.html:
--------------------------------------------------------------------------------
1 | {{ record.get_state_display }}
2 |
--------------------------------------------------------------------------------
/docker-compose.override.yml:
--------------------------------------------------------------------------------
1 | # this file is loaded automatically when running "docker-compose up"
2 | services:
3 | nginx:
4 | ports:
5 | - "8080:8080"
6 |
--------------------------------------------------------------------------------
/docker/environment_variables/rabbitmq.env:
--------------------------------------------------------------------------------
1 | TZ=Europe/Paris
2 | RABBITMQ_DEFAULT_USER=rabbitmq
3 | RABBITMQ_DEFAULT_PASS=rabbitmq
4 | RABBITMQ_DEFAULT_VHOST=squest
5 |
--------------------------------------------------------------------------------
/project-static/squest/img/squest_logo_v2_1417_1417.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HewlettPackard/squest/HEAD/project-static/squest/img/squest_logo_v2_1417_1417.png
--------------------------------------------------------------------------------
/templates/profiles/custom_columns/preview_workflow.html:
--------------------------------------------------------------------------------
1 |
2 | Preview
3 |
4 |
--------------------------------------------------------------------------------
/templates/service_catalog/custom_columns/preview_workflow.html:
--------------------------------------------------------------------------------
1 |
2 | Preview
3 |
4 |
--------------------------------------------------------------------------------
/k8s/squest_k8s/defaults/main.yml:
--------------------------------------------------------------------------------
1 | mariadb_chart_version: 20.5.6
2 | phpmyadmin_chart_version: 18.1.8
3 | rabbitmq_chart_version: 16.0.3
4 | redis_chart_version: 21.1.7
5 |
6 |
7 |
--------------------------------------------------------------------------------
/project-static/squest/img/squest_full_logo_transparent.v1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HewlettPackard/squest/HEAD/project-static/squest/img/squest_full_logo_transparent.v1.png
--------------------------------------------------------------------------------
/templates/generics/ajax-option.html:
--------------------------------------------------------------------------------
1 |
2 | {% for option in options %}
3 |
4 | {% endfor %}
5 |
--------------------------------------------------------------------------------
/templates/generics/custom_columns/generic_actions.html:
--------------------------------------------------------------------------------
1 | {% include 'generics/custom_columns/generic_edit.html' %}
2 | {% include 'generics/custom_columns/generic_delete.html' %}
3 |
--------------------------------------------------------------------------------
/templates/resource_tracker_v2/resource_group/custom_columns/tags.html:
--------------------------------------------------------------------------------
1 | {% for tag in record.tags.all %}
2 | {{ tag }}
3 | {% endfor %}
4 |
--------------------------------------------------------------------------------
/templates/profiles/buttons/manage_all_users.html:
--------------------------------------------------------------------------------
1 |
2 | Manage all users
3 |
4 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/miscellaneous.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Miscellaneous
3 | about: All other issue than bug of feature request
4 | title: ''
5 | labels: ''
6 | assignees: ''
7 |
8 | ---
9 |
10 |
11 |
--------------------------------------------------------------------------------
/docker/scripts/mariadb-init.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | set -e
3 |
4 | mariadb --user=root --password=${MYSQL_ROOT_PASSWORD} <<-EOSQL
5 | GRANT ALL PRIVILEGES ON test_squest_db.* TO '${MYSQL_USER}'@'%';
6 | EOSQL
7 |
--------------------------------------------------------------------------------
/monitoring/urls.py:
--------------------------------------------------------------------------------
1 | from django.urls import path
2 | from monitoring import views
3 |
4 | app_name = 'monitoring'
5 |
6 |
7 | urlpatterns = [
8 | path('', views.metrics, name='metrics'),
9 | ]
10 |
--------------------------------------------------------------------------------
/templates/resource_tracker_v2/resource_group/button_switch_table.html:
--------------------------------------------------------------------------------
1 |
2 | List view
3 |
4 |
--------------------------------------------------------------------------------
/templates/resource_tracker_v2/resource_group/button_switch_csv.html:
--------------------------------------------------------------------------------
1 |
2 | Table view
3 |
4 |
--------------------------------------------------------------------------------
/templates/service_catalog/buttons/instance-archived-list.html:
--------------------------------------------------------------------------------
1 |
2 | Archived instances
3 |
4 |
--------------------------------------------------------------------------------
/templates/service_catalog/buttons/request-archived-list.html:
--------------------------------------------------------------------------------
1 |
2 | Archived requests
3 |
4 |
--------------------------------------------------------------------------------
/templates/service_catalog/custom_columns/service_operations.html:
--------------------------------------------------------------------------------
1 |
2 | {{ record.operations.count }}
3 |
--------------------------------------------------------------------------------
/k8s/squest_k8s/templates/common/labels.yml:
--------------------------------------------------------------------------------
1 | {% if squest_django.extra_labels is defined %}
2 | {% for key, value in squest_django.extra_labels.items() %}
3 | {{ key }}: '{{ value }}'
4 | {% endfor %}
5 | {% endif %}
6 |
--------------------------------------------------------------------------------
/resource_tracker_v2/apps.py:
--------------------------------------------------------------------------------
1 | from django.apps import AppConfig
2 |
3 |
4 | class ResourceTrackerV2Config(AppConfig):
5 | default_auto_field = 'django.db.models.BigAutoField'
6 | name = 'resource_tracker_v2'
7 |
--------------------------------------------------------------------------------
/service_catalog/__init__.py:
--------------------------------------------------------------------------------
1 | # This will make sure the app is always imported when
2 | # Django starts so that shared_task will use this app.
3 | from .celery import app as celery_app
4 |
5 | __all__ = ('celery_app',)
6 |
--------------------------------------------------------------------------------
/templates/service_catalog/buttons/reject_button.html:
--------------------------------------------------------------------------------
1 |
4 | Reject
5 |
6 |
--------------------------------------------------------------------------------
/templates/generics/custom_columns/generic_boolean_check.html:
--------------------------------------------------------------------------------
1 |
8 |
--------------------------------------------------------------------------------
/service_catalog/models/approval_state.py:
--------------------------------------------------------------------------------
1 | from django.db.models import IntegerChoices
2 |
3 |
4 | class ApprovalState(IntegerChoices):
5 | PENDING = 1, 'PENDING'
6 | APPROVED = 2, 'APPROVED'
7 | REJECTED = 3, 'REJECTED'
8 |
--------------------------------------------------------------------------------
/profiles/filters/__init__.py:
--------------------------------------------------------------------------------
1 | from .permission_filter import *
2 | from .notification_filter_filter import *
3 | from .organization_filter import *
4 | from .team_filter import *
5 | from .user_filter import *
6 | from .role_filter import *
7 |
--------------------------------------------------------------------------------
/profiles/filters/role_filter.py:
--------------------------------------------------------------------------------
1 | from Squest.utils.squest_filter import SquestFilter
2 | from profiles.models import Role
3 |
4 |
5 | class RoleFilter(SquestFilter):
6 | class Meta:
7 | model = Role
8 | fields = ['name']
9 |
--------------------------------------------------------------------------------
/templates/resource_tracker_v2/resource_group/custom_columns/resource_group_resource.html:
--------------------------------------------------------------------------------
1 |
4 | {{ record.resources.all|length }}
5 |
6 |
--------------------------------------------------------------------------------
/profiles/forms/__init__.py:
--------------------------------------------------------------------------------
1 | from .token_forms import *
2 | from .request_notification_form import *
3 | from .instance_notification_form import *
4 | from .organization_forms import *
5 | from .role_forms import *
6 | from .globalscope_forms import *
7 |
--------------------------------------------------------------------------------
/profiles/forms/role_forms.py:
--------------------------------------------------------------------------------
1 | from Squest.utils.squest_model_form import SquestModelForm
2 | from profiles.models import Role
3 |
4 |
5 | class RoleForm(SquestModelForm):
6 | class Meta:
7 | model = Role
8 | fields = '__all__'
9 |
--------------------------------------------------------------------------------
/resource_tracker_v2/views/__init__.py:
--------------------------------------------------------------------------------
1 | from .attribute_definition_views import *
2 | from .resource_group_views import *
3 | from .transformer_views import *
4 | from .resource_group_resource_views import *
5 | from .resource_tracker_graph import *
6 |
--------------------------------------------------------------------------------
/templates/service_catalog/buttons/tower_server_new_token.html:
--------------------------------------------------------------------------------
1 |
4 | Update token
5 |
6 |
--------------------------------------------------------------------------------
/profiles/filters/team_filter.py:
--------------------------------------------------------------------------------
1 | from Squest.utils.squest_filter import SquestFilter
2 | from profiles.models.team import Team
3 |
4 |
5 | class TeamFilter(SquestFilter):
6 | class Meta:
7 | model = Team
8 | fields = ['name','org']
9 |
--------------------------------------------------------------------------------
/templates/service_catalog/buttons/manage_docs.html:
--------------------------------------------------------------------------------
1 | {% if request.user.is_staff %}
2 |
3 | Manage docs
4 |
5 | {% endif %}
6 |
--------------------------------------------------------------------------------
/Squest/utils/squest_encoder.py:
--------------------------------------------------------------------------------
1 | from json import JSONEncoder
2 |
3 |
4 | class SquestEncoder(JSONEncoder):
5 | def default(self, obj):
6 | if isinstance(obj, set):
7 | return list(obj)
8 | return JSONEncoder.default(self, obj)
9 |
--------------------------------------------------------------------------------
/templates/resource_tracker_v2/resource_group/custom_columns/resource_group_attributes_button.html:
--------------------------------------------------------------------------------
1 |
4 | {{ record.transformers.all|length }}
5 |
6 |
--------------------------------------------------------------------------------
/profiles/api/serializers/team_serializer.py:
--------------------------------------------------------------------------------
1 | from profiles.api.serializers import ScopeSerializer
2 | from profiles.models import Team
3 |
4 |
5 | class TeamSerializer(ScopeSerializer):
6 | class Meta:
7 | model = Team
8 | fields = '__all__'
9 |
--------------------------------------------------------------------------------
/templates/service_catalog/custom_columns/tower_server_job_templates.html:
--------------------------------------------------------------------------------
1 |
2 | {{ record.jobtemplate_set.all | length }}
3 |
--------------------------------------------------------------------------------
/docker/environment_variables/db.env:
--------------------------------------------------------------------------------
1 | TZ=Europe/Paris
2 | # MySql variables
3 | MYSQL_ROOT_PASSWORD=p@ssw0rd
4 | MYSQL_DATABASE=squest_db
5 | MYSQL_USER=squest_user
6 | MYSQL_PASSWORD=squest_password
7 |
8 | # postgres variables
9 | POSTGRES_PASSWORD=p@ssw0rd
10 |
--------------------------------------------------------------------------------
/profiles/tables/__init__.py:
--------------------------------------------------------------------------------
1 | from .notification_filter_table import *
2 | from .organization_table import *
3 | from .role_table import *
4 | from .team_table import *
5 | from .user_table import *
6 | from .permission_table import *
7 | from .approval_workflow import *
8 |
--------------------------------------------------------------------------------
/templates/service_catalog/admin/service/operation/operation-button-edit-survey.html:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/profiles/forms/team_forms.py:
--------------------------------------------------------------------------------
1 | from Squest.utils.squest_model_form import SquestModelForm
2 | from profiles.models.team import Team
3 |
4 |
5 | class TeamForm(SquestModelForm):
6 | class Meta:
7 | model = Team
8 | fields = ["org", "name", "description", "roles"]
9 |
--------------------------------------------------------------------------------
/templates/resource_tracker_v2/resource_group/resources/resource-delete-button.html:
--------------------------------------------------------------------------------
1 |
3 |
4 |
--------------------------------------------------------------------------------
/profiles/api/serializers/role_serializer.py:
--------------------------------------------------------------------------------
1 | from rest_framework.serializers import ModelSerializer
2 |
3 | from profiles.models import Role
4 |
5 |
6 | class RoleSerializer(ModelSerializer):
7 |
8 | class Meta:
9 | model = Role
10 | fields = '__all__'
11 |
--------------------------------------------------------------------------------
/profiles/filters/organization_filter.py:
--------------------------------------------------------------------------------
1 | from Squest.utils.squest_filter import SquestFilter
2 | from profiles.models.organization import Organization
3 |
4 |
5 | class OrganizationFilter(SquestFilter):
6 | class Meta:
7 | model = Organization
8 | fields = ['name']
9 |
--------------------------------------------------------------------------------
/service_catalog/filters/approval_step_filter.py:
--------------------------------------------------------------------------------
1 | from Squest.utils.squest_filter import SquestFilter
2 | from service_catalog.models import ApprovalStep
3 |
4 |
5 | class ApprovalStepFilter(SquestFilter):
6 | class Meta:
7 | model = ApprovalStep
8 | fields = ["name"]
9 |
--------------------------------------------------------------------------------
/service_catalog/models/exceptions.py:
--------------------------------------------------------------------------------
1 | class ExceptionServiceCatalog:
2 | class JobTemplateNotFound(Exception):
3 | def __init__(self, job_template_id, tower_name):
4 | super().__init__(f"Job Template ID {job_template_id} was not found in the server {tower_name}")
5 |
--------------------------------------------------------------------------------
/templates/resource_tracker_v2/resource_group/resources/resource-edit-button.html:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/service_catalog/filters/service_filter.py:
--------------------------------------------------------------------------------
1 | from Squest.utils.squest_filter import SquestFilter
2 | from service_catalog.models import Service
3 |
4 |
5 | class ServiceFilter(SquestFilter):
6 |
7 | class Meta:
8 | model = Service
9 | fields = ['name', 'enabled']
10 |
--------------------------------------------------------------------------------
/service_catalog/filters/tower_server_filter.py:
--------------------------------------------------------------------------------
1 | from Squest.utils.squest_filter import SquestFilter
2 | from service_catalog.models import TowerServer
3 |
4 |
5 | class TowerServerFilter(SquestFilter):
6 | class Meta:
7 | model = TowerServer
8 | fields = ['name', 'host']
9 |
--------------------------------------------------------------------------------
/service_catalog/filters/portfolio_filter.py:
--------------------------------------------------------------------------------
1 | from Squest.utils.squest_filter import SquestFilter
2 | from service_catalog.models import Portfolio
3 |
4 |
5 | class PortfolioFilter(SquestFilter):
6 | class Meta:
7 | model = Portfolio
8 | fields = ['name', 'parent_portfolio']
9 |
--------------------------------------------------------------------------------
/playbook_examples/squest_inventory/squest_extra_vars/delete.yml:
--------------------------------------------------------------------------------
1 | ---
2 | # fake squest data (make sure to have an instance with ID=1)
3 | squest:
4 | request:
5 | instance:
6 | id: 1
7 | spec:
8 | file_name: 'my_file.txt'
9 | uuid_file: 51b1d14c-cedf-5837-9063-b8cb45f950fe
--------------------------------------------------------------------------------
/profiles/forms/organization_forms.py:
--------------------------------------------------------------------------------
1 | from Squest.utils.squest_model_form import SquestModelForm
2 | from profiles.models import Organization
3 |
4 |
5 | class OrganizationForm(SquestModelForm):
6 | class Meta:
7 | model = Organization
8 | fields = ["name", "description", "roles"]
9 |
--------------------------------------------------------------------------------
/profiles/forms/globalscope_forms.py:
--------------------------------------------------------------------------------
1 | from Squest.utils.squest_model_form import SquestModelForm
2 | from profiles.models import GlobalScope
3 |
4 |
5 | class GlobalScopeForm(SquestModelForm):
6 | class Meta:
7 | model = GlobalScope
8 | fields = ["global_permissions", "owner_permissions"]
9 |
--------------------------------------------------------------------------------
/service_catalog/models/operation_type.py:
--------------------------------------------------------------------------------
1 | from django.db.models import TextChoices
2 | from django.utils.translation import gettext_lazy as _
3 |
4 |
5 | class OperationType(TextChoices):
6 | CREATE = 'CREATE', _('Create')
7 | UPDATE = 'UPDATE', _('Update')
8 | DELETE = 'DELETE', _('Delete')
9 |
--------------------------------------------------------------------------------
/profiles/api/serializers/contenttype_serializer.py:
--------------------------------------------------------------------------------
1 | from django.contrib.contenttypes.models import ContentType
2 | from rest_framework.serializers import ModelSerializer
3 |
4 |
5 | class ContentTypeSerializer(ModelSerializer):
6 | class Meta:
7 | model = ContentType
8 | fields = '__all__'
9 |
--------------------------------------------------------------------------------
/docker/maintenance.nginx.conf:
--------------------------------------------------------------------------------
1 | server {
2 | root /usr/share/nginx/html;
3 | listen 80;
4 | location / {
5 | try_files $uri $uri/ /index.html;
6 | }
7 | location ~ \.(ttf|ttc|otf|eot|woff|font.css|css|js)$ {
8 | add_header Access-Control-Allow-Origin "*";
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/docker/scripts/psql-init.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | set -e
3 |
4 | psql <<-EOSQL
5 | CREATE USER ${DB_USER} PASSWORD '${DB_PASSWORD}' NOSUPERUSER CREATEDB CREATEROLE INHERIT LOGIN;
6 | CREATE DATABASE ${DB_DATABASE} OWNER ${DB_USER};
7 | GRANT ALL PRIVILEGES ON `test\_squest\_db` . * TO '${DB_USER}'@'%';
8 | EOSQL
--------------------------------------------------------------------------------
/resource_tracker_v2/filters/resource_group_filter.py:
--------------------------------------------------------------------------------
1 | from resource_tracker_v2.filters.tag_filter import TagFilterset
2 | from resource_tracker_v2.models import ResourceGroup
3 |
4 |
5 | class ResourceGroupFilter(TagFilterset):
6 | class Meta:
7 | model = ResourceGroup
8 | fields = ['name', 'tag']
9 |
--------------------------------------------------------------------------------
/service_catalog/filters/job_template_filter.py:
--------------------------------------------------------------------------------
1 | from Squest.utils.squest_filter import SquestFilter
2 | from service_catalog.models import JobTemplate
3 |
4 |
5 | class JobTemplateFilter(SquestFilter):
6 | class Meta:
7 | model = JobTemplate
8 | fields = ['tower_server', 'name', 'is_compliant']
9 |
--------------------------------------------------------------------------------
/profiles/api/serializers/permission_serializers.py:
--------------------------------------------------------------------------------
1 | from rest_framework.serializers import ModelSerializer
2 |
3 | from profiles.models.squest_permission import Permission
4 |
5 |
6 | class PermissionSerializer(ModelSerializer):
7 | class Meta:
8 | model = Permission
9 | fields = '__all__'
10 |
--------------------------------------------------------------------------------
/k8s/squest_k8s/templates/squest_secrets.yaml:
--------------------------------------------------------------------------------
1 | kind: Secret
2 | apiVersion: v1
3 | metadata:
4 | name: "squest-secrets"
5 | labels:
6 | app: squest
7 | service: django
8 | data:
9 | {% for key, value in squest_django.env_secrets.items() %}
10 | {{ key }}: "{{ value | b64encode }}"
11 | {% endfor %}
12 |
--------------------------------------------------------------------------------
/templates/generics/buttons/bulk_delete_button.html:
--------------------------------------------------------------------------------
1 | {% has_perm request.user django_content_type.app_label|add:".delete_"|add:django_content_type.model as can_delete %}
2 | {% if can_delete %}
3 |
6 | {% endif %}
7 |
--------------------------------------------------------------------------------
/templates/resource_tracker_v2/resource_group/resources/resource-move-button.html:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/service_catalog/filters/approval_workflow_filter.py:
--------------------------------------------------------------------------------
1 | from Squest.utils.squest_filter import SquestFilter
2 | from service_catalog.models.approval_workflow import ApprovalWorkflow
3 |
4 |
5 | class ApprovalWorkflowFilter(SquestFilter):
6 | class Meta:
7 | model = ApprovalWorkflow
8 | fields = ["name", "enabled"]
9 |
--------------------------------------------------------------------------------
/resource_tracker_v2/filters/attribute_definition_filter.py:
--------------------------------------------------------------------------------
1 | from Squest.utils.squest_filter import SquestFilter
2 | from resource_tracker_v2.models import AttributeDefinition
3 |
4 |
5 | class AttributeDefinitionFilter(SquestFilter):
6 | class Meta:
7 | model = AttributeDefinition
8 | fields = ['name', 'services']
9 |
--------------------------------------------------------------------------------
/service_catalog/api/serializers/task_result_serializer.py:
--------------------------------------------------------------------------------
1 | from django_celery_results.models import TaskResult
2 | from rest_framework import serializers
3 |
4 |
5 | class TaskResultSerializer(serializers.ModelSerializer):
6 | class Meta:
7 | model = TaskResult
8 | fields = ['id', 'meta', 'status']
9 |
10 |
--------------------------------------------------------------------------------
/service_catalog/forms/request_forms.py:
--------------------------------------------------------------------------------
1 | from Squest.utils.squest_model_form import SquestModelForm
2 | from service_catalog.models import Request
3 |
4 |
5 | class RequestForm(SquestModelForm):
6 | class Meta:
7 | model = Request
8 | exclude = ["periodic_task", "periodic_task_date_expire", "approval_workflow_state"]
9 |
--------------------------------------------------------------------------------
/service_catalog/models/bootstrap_type.py:
--------------------------------------------------------------------------------
1 | from django.db.models import TextChoices
2 | from django.utils.translation import gettext_lazy as _
3 |
4 |
5 | class BootstrapType(TextChoices):
6 | SUCCESS = 'SUCCESS', _('SUCCESS')
7 | DANGER = 'DANGER', _('DANGER')
8 | WARNING = 'WARNING', _('WARNING')
9 | INFO = 'INFO', _('INFO')
--------------------------------------------------------------------------------
/templates/service_catalog/custom_columns/service_actions.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | {% include 'generics/custom_columns/generic_actions.html' %}
5 |
--------------------------------------------------------------------------------
/resource_tracker_v2/filters/resource_filter.py:
--------------------------------------------------------------------------------
1 | from resource_tracker_v2.filters.tag_filter import TagFilterset
2 | from resource_tracker_v2.models import Resource
3 |
4 |
5 | class ResourceFilter(TagFilterset):
6 | class Meta:
7 | model = Resource
8 | fields = ['resource_group','service_catalog_instance', 'name', 'tag']
9 |
--------------------------------------------------------------------------------
/resource_tracker_v2/filters/transformer_filter.py:
--------------------------------------------------------------------------------
1 | from Squest.utils.squest_filter import SquestFilter
2 | from resource_tracker_v2.models import Transformer
3 |
4 |
5 | class TransformerFilter(SquestFilter):
6 |
7 | class Meta:
8 | model = Transformer
9 | fields = ['resource_group', 'attribute_definition']
10 |
--------------------------------------------------------------------------------
/profiles/api/serializers/globalscope_serializer.py:
--------------------------------------------------------------------------------
1 | from profiles.api.serializers import AbstractScopeSerializer
2 | from profiles.models import GlobalScope
3 |
4 |
5 | class GlobalScopeSerializer(AbstractScopeSerializer):
6 | class Meta:
7 | model = GlobalScope
8 | fields = ('global_permissions', 'owner_permissions', 'rbac')
9 |
--------------------------------------------------------------------------------
/service_catalog/models/squest_settings.py:
--------------------------------------------------------------------------------
1 | from django.contrib import admin
2 | from django.db.models import BooleanField
3 |
4 | from Squest.models.singleton_model import SingletonModel
5 |
6 |
7 | class SquestSettings(SingletonModel):
8 | maintenance_mode_enabled = BooleanField(default=False)
9 |
10 |
11 | admin.site.register(SquestSettings)
12 |
--------------------------------------------------------------------------------
/templates/generics/buttons/add_button.html:
--------------------------------------------------------------------------------
1 | {% with perm=django_content_type.app_label|add:".add_"|add:django_content_type.model %}
2 | {% has_perm request.user perm as can_add %}
3 | {% if can_add %}
4 |
5 | Add
6 |
7 | {% endif %}
8 | {% endwith %}
9 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "dependencies": {
3 | "@highlightjs/cdn-assets": "^11.4.0",
4 | "admin-lte": "^3.1.0",
5 | "bootstrap": "^4.6.1",
6 | "bootstrap-select": "^1.13.18",
7 | "datatables.net": "^1.13.1",
8 | "datatables.net-bs4": "^1.13.1",
9 | "datatables.net-buttons": "^2.3.3",
10 | "datatables.net-buttons-bs4": "^2.3.3"
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/playbook_examples/squest_inventory/squest_extra_vars/update.yml:
--------------------------------------------------------------------------------
1 | ---
2 | # survey variables
3 | file_content: 'this is my content'
4 |
5 | # fake squest data (make sure to have an instance with ID=1)
6 | squest:
7 | request:
8 | instance:
9 | id: 1
10 | spec:
11 | file_name: 'my_file.txt'
12 | uuid_file: 51b1d14c-cedf-5837-9063-b8cb45f950fe
--------------------------------------------------------------------------------
/service_catalog/forms/custom_link_form.py:
--------------------------------------------------------------------------------
1 | from Squest.utils.squest_model_form import SquestModelForm
2 | from service_catalog.models.custom_link import CustomLink
3 |
4 |
5 | class CustomLinkForm(SquestModelForm):
6 | class Meta:
7 | model = CustomLink
8 | fields = ["name", "services", "text", "url", "button_class", "when", "loop", "enabled", "is_admin_only"]
9 |
--------------------------------------------------------------------------------
/templates/profiles/forms/form_headers/instance_notification_filter_header.html:
--------------------------------------------------------------------------------
1 |
2 |
Support notification filter
3 |
When: Ansible like condition. instance is available in the context.
4 |
E.g: Access the instance spec: instance.spec['location'] == 'grenoble'
5 |
6 |
--------------------------------------------------------------------------------
/resource_tracker_v2/api/serializers/attribute_definition_serializers.py:
--------------------------------------------------------------------------------
1 | from rest_framework import serializers
2 |
3 | from resource_tracker_v2.models import AttributeDefinition
4 |
5 |
6 | class AttributeDefinitionSerializer(serializers.ModelSerializer):
7 |
8 | class Meta:
9 | model = AttributeDefinition
10 | fields = ["id", "name", "description"]
11 |
--------------------------------------------------------------------------------
/templates/service_catalog/buttons/operation_survey_button.html:
--------------------------------------------------------------------------------
1 | {% has_perm request.user "service_catalog.change_operation" as can_change %}
2 | {% if can_change %}
3 |
5 | Survey
6 |
7 | {% endif %}
8 |
--------------------------------------------------------------------------------
/resource_tracker_v2/models/__init__.py:
--------------------------------------------------------------------------------
1 | from resource_tracker_v2.models.attribute_definition import AttributeDefinition
2 | from resource_tracker_v2.models.transformer import Transformer
3 | from resource_tracker_v2.models.resource import Resource
4 | from resource_tracker_v2.models.resource_attribute import ResourceAttribute
5 | from resource_tracker_v2.models.resource_group import ResourceGroup
6 |
--------------------------------------------------------------------------------
/profiles/api/serializers/rbac_serializers.py:
--------------------------------------------------------------------------------
1 | from rest_framework.serializers import ModelSerializer
2 |
3 | from profiles.api.serializers import RoleSerializer
4 | from profiles.models import RBAC
5 |
6 |
7 | class RBACSerializer(ModelSerializer):
8 | role = RoleSerializer(read_only=True)
9 |
10 | class Meta:
11 | model = RBAC
12 | fields = ['role', 'user_set']
13 |
--------------------------------------------------------------------------------
/service_catalog/filters/email_template_filter.py:
--------------------------------------------------------------------------------
1 | from django.forms import SelectMultiple
2 | from django_filters import MultipleChoiceFilter
3 |
4 | from Squest.utils.squest_filter import SquestFilter
5 | from service_catalog.models import EmailTemplate
6 |
7 |
8 | class EmailTemplateFilter(SquestFilter):
9 | class Meta:
10 | model = EmailTemplate
11 | fields = ['name']
12 |
--------------------------------------------------------------------------------
/templates/service_catalog/custom_columns/create_operation_request.html:
--------------------------------------------------------------------------------
1 | {% has_perm request.user record.permission.permission_str as can_request_operation %}
2 | {% if can_request_operation %}
3 |
5 |
6 |
7 | {% endif %}
--------------------------------------------------------------------------------
/service_catalog/api/serializers/job_template_serializer.py:
--------------------------------------------------------------------------------
1 | from rest_framework import serializers
2 |
3 | from service_catalog.models import JobTemplate
4 |
5 |
6 | class JobTemplateSerializer(serializers.ModelSerializer):
7 | class Meta:
8 | model = JobTemplate
9 | fields = '__all__'
10 | read_only_fields = ['tower_id', 'tower_server', 'survey', 'tower_job_template_data']
11 |
--------------------------------------------------------------------------------
/project-static/squest/js/dashboards.js:
--------------------------------------------------------------------------------
1 | function createPieChart(data, id) {
2 |
3 | var config = {
4 | type: 'pie',
5 | data: data,
6 | options: {
7 | responsive: true,
8 | maintainAspectRatio: false,
9 |
10 | }
11 | };
12 |
13 | var ctx = document.getElementById(id).getContext('2d');
14 | window.myPie = new Chart(ctx, config);
15 | }
16 |
--------------------------------------------------------------------------------
/playbook_examples/squest_inventory/squest_extra_vars/create.yml:
--------------------------------------------------------------------------------
1 | ---
2 | # user provided survey variables
3 | file_name: 'my_file.txt'
4 | file_content: 'this is my content'
5 | # admin provided survey variables
6 | create_resource: False
7 |
8 | # fake squest data (make sure to have an instance with ID=1)
9 | squest:
10 | request:
11 | instance:
12 | id: 1
13 | name: "My file"
14 | spec: { }
15 |
--------------------------------------------------------------------------------
/templates/resource_tracker_v2/resource_group/resources/custom_columns/resource_operations.html:
--------------------------------------------------------------------------------
1 | {% include 'resource_tracker_v2/resource_group/resources/resource-move-button.html' with resource=record %}
2 | {% include 'resource_tracker_v2/resource_group/resources/resource-edit-button.html' with resource=record %}
3 | {% include 'resource_tracker_v2/resource_group/resources/resource-delete-button.html' with resource=record %}
4 |
--------------------------------------------------------------------------------
/templates/service_catalog/buttons/delete_operation_button.html:
--------------------------------------------------------------------------------
1 | {% with perm="service_catalog.delete_operation" %}
2 | {% has_perm request.user perm object as can_delete %}
3 | {% if can_delete %}
4 |
6 |
7 |
8 | {% endif %}
9 | {% endwith %}
10 |
--------------------------------------------------------------------------------
/playbook_examples/squest_inventory/group_vars/squest_testing.yml:
--------------------------------------------------------------------------------
1 | ---
2 | # playbook variable
3 | squest_token: "xxxxxxxxxxxaaaaaeeee1234"
4 | squest_bearer_token: "Bearer {{ squest_token }}"
5 |
6 | # Resource tracking : resource group ID to create a new resource when provisioning the service (make sure to have a resource group with ID=1)
7 | resource_group_file_id: 1
8 |
9 | squest_api: "http://127.0.0.1:8000/api"
10 |
--------------------------------------------------------------------------------
/service_catalog/models/request_state.py:
--------------------------------------------------------------------------------
1 | from django.db.models import IntegerChoices
2 |
3 |
4 | class RequestState(IntegerChoices):
5 | SUBMITTED = 1, "SUBMITTED"
6 | ON_HOLD = 2, "ON_HOLD"
7 | REJECTED = 3, "REJECTED"
8 | CANCELED = 4, "CANCELED"
9 | ACCEPTED = 5, "ACCEPTED"
10 | PROCESSING = 6, "PROCESSING"
11 | COMPLETE = 7, "COMPLETE"
12 | FAILED = 8, "FAILED"
13 | ARCHIVED = 9, "ARCHIVED"
14 |
--------------------------------------------------------------------------------
/templates/service_catalog/custom_columns/global_hook_state.html:
--------------------------------------------------------------------------------
1 | {% if record.model == "Instance" %}
2 | {{ record.get_state_display }}
3 | {% elif record.model == "Request" %}
4 | {{ record.get_state_display }}
5 | {% else %}
6 | {{ record.get_state_display }}
7 | {% endif %}
8 |
--------------------------------------------------------------------------------
/templates/service_catalog/buttons/edit_operation_button.html:
--------------------------------------------------------------------------------
1 | {% with perm="service_catalog.change_operation" %}
2 | {% has_perm request.user perm object as can_change %}
3 | {% if can_change %}
4 |
6 |
7 |
8 | {% endif %}
9 | {% endwith %}
10 |
--------------------------------------------------------------------------------
/service_catalog/api/serializers/custom_link_serializer.py:
--------------------------------------------------------------------------------
1 | from rest_framework.serializers import ModelSerializer
2 |
3 | from service_catalog.models import CustomLink
4 |
5 |
6 | class CustomLinkSerializer(ModelSerializer):
7 | class Meta:
8 | model = CustomLink
9 | fields = ('id', 'name', 'services', 'text', 'url', 'button_class', 'when', 'loop', 'enabled', 'is_admin_only')
10 | read_only_fields = ('id',)
11 |
--------------------------------------------------------------------------------
/service_catalog/forms/doc_forms.py:
--------------------------------------------------------------------------------
1 | from martor.fields import MartorFormField
2 | from martor.widgets import AdminMartorWidget
3 |
4 | from Squest.utils.squest_model_form import SquestModelForm
5 | from service_catalog.models.documentation import Doc
6 |
7 |
8 | class DocForm(SquestModelForm):
9 | content = MartorFormField(widget=AdminMartorWidget())
10 |
11 | class Meta:
12 | model = Doc
13 | fields = '__all__'
14 |
--------------------------------------------------------------------------------
/playbook_examples/squest_inventory/README.md:
--------------------------------------------------------------------------------
1 | # Inventory usage
2 |
3 | Please replace all variables in upercase in this directory:
4 |
5 | In inventory replace:
6 | - `localhost ansible_connection=local` by your machine host where playbooks will be executed
7 |
8 | In group_vars/squest_testing.yml replace:
9 | - `SQUEST_TOKEN` by a token generated in Squest by an admin
10 | - `SQUEST_API_URL` the URL of your Squest API (e.g. localhost:8000)
--------------------------------------------------------------------------------
/docker/entrypoint.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | echo "Applying database migration"
4 | python manage.py migrate --database=${DATABASE:-default}
5 |
6 | echo "Collect static files"
7 | python manage.py collectstatic --noinput
8 |
9 | echo "Inserting default data"
10 | python manage.py insert_default_data
11 |
12 | echo "Starting web server"
13 | gunicorn --bind 0.0.0.0:8000 --workers ${GUNICORN_WORKERS:-4} --pythonpath /app/squest Squest.wsgi
14 |
--------------------------------------------------------------------------------
/service_catalog/templatetags/maintenance.py:
--------------------------------------------------------------------------------
1 | from django import template
2 | from django.conf import settings
3 |
4 | from service_catalog.models import SquestSettings
5 |
6 | register = template.Library()
7 |
8 |
9 | @register.simple_tag()
10 | def is_maintenance_mode_enabled():
11 | return SquestSettings.load().maintenance_mode_enabled
12 |
13 |
14 | @register.simple_tag()
15 | def is_dev_server():
16 | return settings.IS_DEV_SERVER
17 |
--------------------------------------------------------------------------------
/templates/service_catalog/custom_columns/job_template_compliant.html:
--------------------------------------------------------------------------------
1 |
3 |
10 |
11 |
--------------------------------------------------------------------------------
/Squest/wsgi.py:
--------------------------------------------------------------------------------
1 | """
2 | WSGI config for Squest project.
3 |
4 | It exposes the WSGI callable as a module-level variable named ``application``.
5 |
6 | For more information on this file, see
7 | https://docs.djangoproject.com/en/3.1/howto/deployment/wsgi/
8 | """
9 |
10 | import os
11 | from django.core.wsgi import get_wsgi_application
12 |
13 | os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'Squest.settings')
14 | application = get_wsgi_application()
15 |
--------------------------------------------------------------------------------
/service_catalog/api/serializers/portfolio_serializer.py:
--------------------------------------------------------------------------------
1 | from rest_framework.serializers import ModelSerializer
2 |
3 | from service_catalog.models import Portfolio
4 |
5 |
6 | class PortfolioSerializer(ModelSerializer):
7 | class Meta:
8 | model = Portfolio
9 | fields = ('id', 'name', 'description', 'parent_portfolio', 'image', 'portfolio_list', 'service_list')
10 | read_only_fields = ('id', 'portfolio_list', 'service_list')
11 |
--------------------------------------------------------------------------------
/service_catalog/api/serializers/__init__.py:
--------------------------------------------------------------------------------
1 | from .accept_request_serializer import *
2 | from .dynamic_survey_serializer import *
3 | from .instance_serializer import *
4 | from .job_template_serializer import *
5 | from .operation_serializers import *
6 | from .request_message_serializer import *
7 | from .request_serializers import *
8 | from .service_serializers import *
9 | from .task_result_serializer import *
10 | from .tower_server_serializer import *
11 |
--------------------------------------------------------------------------------
/tests/test_service_catalog/test_views/test_admin/test_tools/test_tower/base_test_tower.py:
--------------------------------------------------------------------------------
1 | from django_celery_results.models import TaskResult
2 |
3 | from service_catalog.models import Request, Instance, TowerServer
4 | from tests.test_service_catalog.base import BaseTest
5 |
6 |
7 | class BaseTestTower(BaseTest):
8 |
9 | def setUp(self):
10 | super(BaseTestTower, self).setUp()
11 |
12 | self.test_task_result = TaskResult.objects.create()
13 |
--------------------------------------------------------------------------------
/profiles/api/serializers/organization_serializer.py:
--------------------------------------------------------------------------------
1 | from profiles.api.serializers import ScopeSerializer
2 | from profiles.api.serializers.quota_serializer import QuotaSerializer
3 | from profiles.models import Organization
4 |
5 |
6 | class OrganizationSerializer(ScopeSerializer):
7 | class Meta:
8 | model = Organization
9 | fields = '__all__'
10 | read_only_fields = ['teams', ]
11 |
12 | quotas = QuotaSerializer(many=True, read_only=True)
13 |
--------------------------------------------------------------------------------
/profiles/migrations/0013_delete_billinggroup.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 3.2.13 on 2023-06-22 15:29
2 |
3 | from django.db import migrations
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [
9 | ('service_catalog', '0014_auto_20230622_1722'),
10 | ('profiles', '0012_auto_20230622_1722'),
11 | ]
12 |
13 | operations = [
14 | migrations.DeleteModel(
15 | name='BillingGroup',
16 | ),
17 | ]
18 |
--------------------------------------------------------------------------------
/Squest/asgi.py:
--------------------------------------------------------------------------------
1 | """
2 | ASGI config for Squest project.
3 |
4 | It exposes the ASGI callable as a module-level variable named ``application``.
5 |
6 | For more information on this file, see
7 | https://docs.djangoproject.com/en/3.1/howto/deployment/asgi/
8 | """
9 |
10 | import os
11 |
12 | from django.core.asgi import get_asgi_application
13 |
14 | os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'Squest.settings.development')
15 |
16 | application = get_asgi_application()
17 |
--------------------------------------------------------------------------------
/service_catalog/filters/global_hook_filter.py:
--------------------------------------------------------------------------------
1 | from Squest.utils.squest_filter import SquestFilter
2 | from service_catalog.models import InstanceHook, RequestHook
3 |
4 |
5 | class InstanceHookFilter(SquestFilter):
6 | class Meta:
7 | model = InstanceHook
8 | fields = ['name', 'state', 'services']
9 |
10 |
11 | class RequestHookFilter(SquestFilter):
12 | class Meta:
13 | model = RequestHook
14 | fields = ['name', 'state', 'operations']
15 |
--------------------------------------------------------------------------------
/dev.docker-compose.yml:
--------------------------------------------------------------------------------
1 | # add this file to the docker compose execution when developing Squest
2 | services:
3 |
4 | db:
5 | ports:
6 | - "3306:3306"
7 |
8 | phpmyadmin:
9 | image: phpmyadmin/phpmyadmin:5.1.3
10 | env_file: docker/environment_variables/phpmyadmin.env
11 | ports:
12 | - "8082:80"
13 |
14 | rabbitmq:
15 | ports:
16 | - "15672:15672"
17 | - "5672:5672"
18 |
19 | redis-cache:
20 | ports:
21 | - "6379:6379"
22 |
--------------------------------------------------------------------------------
/resource_tracker_v2/api/serializers/resource_group_serializers.py:
--------------------------------------------------------------------------------
1 | from rest_framework import serializers
2 | from taggit.serializers import TagListSerializerField, TaggitSerializer
3 |
4 | from resource_tracker_v2.models import ResourceGroup
5 |
6 |
7 | class ResourceGroupSerializer(TaggitSerializer, serializers.ModelSerializer):
8 |
9 | tags = TagListSerializerField()
10 |
11 | class Meta:
12 | model = ResourceGroup
13 | fields = ["id", "name", "tags"]
14 |
--------------------------------------------------------------------------------
/k8s/.ansible-lint:
--------------------------------------------------------------------------------
1 | ---
2 |
3 | profile: production
4 |
5 | skip_list:
6 | - key-order
7 | - no-changed-when
8 | - yaml[line-length]
9 |
10 | enable_list:
11 | - args
12 | - empty-string-compare # opt-in
13 | - no-log-password # opt-in
14 | - no-same-owner # opt-in
15 | - galaxy-version-incorrect # opt-in
16 | # add yaml here if you want to avoid ignoring yaml checks when yamllint
17 | # library is missing. Normally its absence just skips using that rule.
18 | - yaml
19 |
--------------------------------------------------------------------------------
/profiles/filters/notification_filter_filter.py:
--------------------------------------------------------------------------------
1 | from Squest.utils.squest_filter import SquestFilter
2 | from profiles.models import RequestNotification, InstanceNotification
3 |
4 |
5 | class RequestNotificationFilterFilter(SquestFilter):
6 | class Meta:
7 | model = RequestNotification
8 | fields = ['name']
9 |
10 |
11 | class InstanceNotificationFilterFilter(SquestFilter):
12 | class Meta:
13 | model = InstanceNotification
14 | fields = ['name']
15 |
--------------------------------------------------------------------------------
/profiles/filters/quota.py:
--------------------------------------------------------------------------------
1 | from Squest.utils.squest_filter import SquestFilter
2 | from profiles.models import Quota
3 |
4 |
5 | class QuotaFilter(SquestFilter):
6 | class Meta:
7 | model = Quota
8 | fields = ['scope', 'attribute_definition', 'attribute_definition__services']
9 |
10 | def __init__(self, *args, **kwargs):
11 | super(QuotaFilter, self).__init__(*args, **kwargs)
12 | self.filters['attribute_definition__services'].field.label = 'Services'
13 |
--------------------------------------------------------------------------------
/templates/profiles/custom_columns/delete_all_user_roles.html:
--------------------------------------------------------------------------------
1 | {# can_delete_user come from {organization,team,globalscope}_detail.html#}
2 | {% with class_name=object|to_class_name|lower %}
3 | {% if can_delete_user %}
4 |
7 |
8 |
9 | {% endif %}
10 | {% endwith %}
11 |
--------------------------------------------------------------------------------
/service_catalog/migrations/0045_alter_doc_options.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 4.2.13 on 2025-05-19 13:46
2 |
3 | from django.db import migrations
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [
9 | ('service_catalog', '0044_alter_operation_options_operation_permission'),
10 | ]
11 |
12 | operations = [
13 | migrations.AlterModelOptions(
14 | name='doc',
15 | options={'ordering': ['title']},
16 | ),
17 | ]
18 |
--------------------------------------------------------------------------------
/profiles/filters/permission_filter.py:
--------------------------------------------------------------------------------
1 | from Squest.utils.squest_filter import SquestFilter
2 | from profiles.models.squest_permission import Permission
3 |
4 |
5 | class PermissionFilter(SquestFilter):
6 | class Meta:
7 | model = Permission
8 | fields = ['name', 'codename', 'content_type__model']
9 |
10 | def __init__(self, *args, **kwargs):
11 | super(PermissionFilter, self).__init__(*args, **kwargs)
12 | self.filters['content_type__model'].field.label = 'Model'
13 |
--------------------------------------------------------------------------------
/profiles/migrations/0015_profile_theme.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 3.2.13 on 2023-06-30 14:19
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [
9 | ('profiles', '0014_quota'),
10 | ]
11 |
12 | operations = [
13 | migrations.AddField(
14 | model_name='profile',
15 | name='theme',
16 | field=models.CharField(default='dark', max_length=20),
17 | ),
18 | ]
19 |
--------------------------------------------------------------------------------
/templates/resource_tracker_v2/resource_group/custom_columns/resource_group_attribute_actions.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/templates/resource_tracker_v2/resource_group/resources/resource_list_buttons.html:
--------------------------------------------------------------------------------
1 | {% include 'generics/buttons/bulk_delete_button.html' %}
2 |
4 | Add
5 |
6 |
8 | Edit resource group
9 |
10 |
--------------------------------------------------------------------------------
/service_catalog/forms/__init__.py:
--------------------------------------------------------------------------------
1 | from .portfolio_form import *
2 | from .announcement_form import *
3 | from .doc_forms import *
4 | from .global_hook_forms import *
5 | from .instance_forms import *
6 | from .operation_forms import *
7 | from .operation_request_forms import *
8 | from .request_message_forms import *
9 | from .service_forms import *
10 | from .service_request_forms import *
11 | from .support_message_forms import *
12 | from .support_request_forms import *
13 | from .tower_server_forms import *
--------------------------------------------------------------------------------
/tls.docker-compose.yml:
--------------------------------------------------------------------------------
1 | # docker-compose -f docker-compose.yml -f tls.docker-compose.yml up
2 | version: '3.7'
3 |
4 | services:
5 | tls:
6 | image: caddy:2.6.4-alpine
7 | depends_on:
8 | - nginx
9 | volumes:
10 | - ./docker/certs/squest.crt:/etc/ssl/private/squest.crt
11 | - ./docker/certs/squest.key:/etc/ssl/private/squest.key
12 | - ./docker/Caddyfile:/etc/caddy/Caddyfile:ro
13 | ports:
14 | - "80:80" # Allows for http redirection
15 | - "443:443"
16 |
--------------------------------------------------------------------------------
/service_catalog/tables/doc_tables.py:
--------------------------------------------------------------------------------
1 | from django_tables2 import TemplateColumn, LinkColumn
2 | from django_tables2.utils import A
3 |
4 | from Squest.utils.squest_table import SquestTable
5 | from service_catalog.models import Doc
6 |
7 |
8 | class DocTable(SquestTable):
9 | title = LinkColumn("service_catalog:doc_details", args=[A("id")])
10 |
11 | class Meta:
12 | model = Doc
13 | attrs = {"id": "doc_table", "class": "table squest-pagination-tables"}
14 | fields = ("title",)
15 |
--------------------------------------------------------------------------------
/profiles/api/views/__init__.py:
--------------------------------------------------------------------------------
1 | from .permission_api_views import *
2 | from .organization_api_views import *
3 | from .requestnotification import *
4 | from .instancenotification import *
5 | from .team_api_views import *
6 | from .user_api_views import *
7 |
8 | from .requestnotification import *
9 | from .instancenotification import *
10 | from .user_api_views import *
11 | from .role_api_views import *
12 | from .globalscope_api_views import *
13 | from .scope_api_views import *
14 | from .quota_api_views import *
15 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature_request.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Feature request
3 | about: Suggest an idea for this project
4 | title: ''
5 | labels: ''
6 | assignees: ''
7 |
8 | ---
9 |
10 | **Description of the feature**
11 | A clear and concise description of what the problem is.
12 | Ex. I would like to be able to [...]
13 |
14 | **Describe the solution you'd like**
15 | A clear and concise description of what you want to happen.
16 | Keep in mind that the Squest project trend to keep a generic approach for all features.
17 |
--------------------------------------------------------------------------------
/templates/profiles/forms/form_headers/request_notification_filter_header.html:
--------------------------------------------------------------------------------
1 |
2 |
Request notification filter
3 |
When: Ansible like condition. request is available in the context.
4 |
E.g with a day 1 operation. Access the user survey: request.fill_in_survey['location'] == 'grenoble'
5 |
E.g with a day 2 operation. Access the spec of instance: request.instance.spec['configvar'] == 'value'
6 |
7 |
--------------------------------------------------------------------------------
/profiles/tables/team_quota_limit_table.py:
--------------------------------------------------------------------------------
1 | from django_tables2 import LinkColumn
2 |
3 | from Squest.utils.squest_table import SquestTable
4 | from profiles.models import Quota
5 |
6 |
7 | class TeamQuotaLimitTable(SquestTable):
8 | scope = LinkColumn()
9 | limit = LinkColumn()
10 | consumed = LinkColumn(orderable=False)
11 |
12 | class Meta:
13 | model = Quota
14 | attrs = {"id": "quota_team_table", "class": "table squest-pagination-tables"}
15 | fields = ("scope", "limit", "consumed")
16 |
--------------------------------------------------------------------------------
/templates/service_catalog/custom_columns/operation_request.html:
--------------------------------------------------------------------------------
1 |
7 |
--------------------------------------------------------------------------------
/resource_tracker_v2/migrations/0004_alter_transformer_factor.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 3.2.13 on 2023-07-24 18:58
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [
9 | ('resource_tracker_v2', '0003_auto_20230724_0940'),
10 | ]
11 |
12 | operations = [
13 | migrations.AlterField(
14 | model_name='transformer',
15 | name='factor',
16 | field=models.FloatField(default=1),
17 | ),
18 | ]
19 |
--------------------------------------------------------------------------------
/service_catalog/migrations/0046_alter_doc_options.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 4.2.13 on 2025-05-22 12:00
2 |
3 | from django.db import migrations
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [
9 | ('service_catalog', '0045_alter_doc_options'),
10 | ]
11 |
12 | operations = [
13 | migrations.AlterModelOptions(
14 | name='doc',
15 | options={'default_permissions': ('add', 'change', 'delete', 'view', 'list'), 'ordering': ['title']},
16 | ),
17 | ]
18 |
--------------------------------------------------------------------------------
/service_catalog/forms/global_hook_forms.py:
--------------------------------------------------------------------------------
1 | from Squest.utils.squest_model_form import SquestModelForm
2 | from service_catalog.models import InstanceHook, RequestHook
3 |
4 |
5 | class InstanceHookForm(SquestModelForm):
6 | class Meta:
7 | model = InstanceHook
8 | fields = ["name", "services", "state", "job_template", "extra_vars"]
9 |
10 |
11 | class RequestHookForm(SquestModelForm):
12 | class Meta:
13 | model = RequestHook
14 | fields = ["name", "operations", "state", "job_template", "extra_vars"]
15 |
--------------------------------------------------------------------------------
/service_catalog/models/instance_state.py:
--------------------------------------------------------------------------------
1 | from django.db.models import IntegerChoices
2 |
3 |
4 | class InstanceState(IntegerChoices):
5 | PENDING = 1, "PENDING"
6 | PROVISION_FAILED = 2, "PROVISION_FAILED"
7 | PROVISIONING = 3, "PROVISIONING"
8 | UPDATING = 4, "UPDATING"
9 | UPDATE_FAILED = 5, "UPDATE_FAILED"
10 | DELETING = 6, "DELETING"
11 | DELETED = 7, "DELETED"
12 | DELETE_FAILED = 8, "DELETE_FAILED"
13 | ARCHIVED = 9, "ARCHIVED"
14 | AVAILABLE = 10, "AVAILABLE"
15 | ABORTED = 11, "ABORTED"
16 |
--------------------------------------------------------------------------------
/tests/test_resource_tracker_v2/test_model/test_attribute_definition.py:
--------------------------------------------------------------------------------
1 | from tests.test_resource_tracker_v2.base_test_resource_tracker_v2 import BaseTestResourceTrackerV2
2 |
3 |
4 | class TestModelAttributeDefinition(BaseTestResourceTrackerV2):
5 |
6 | def setUp(self) -> None:
7 | super(TestModelAttributeDefinition, self).setUp()
8 |
9 | def test_delete_attribute_definition(self):
10 | self._validate_state_before_deletion()
11 | self.vcpu_attribute.delete()
12 | self._validate_state_after_deletion()
13 |
--------------------------------------------------------------------------------
/profiles/views/__init__.py:
--------------------------------------------------------------------------------
1 | from profiles.views.team import *
2 | from profiles.views.token import *
3 | from profiles.views.profile import *
4 | from profiles.views.request_notification_views import *
5 | from profiles.views.instance_notification_views import *
6 | from profiles.views.organization import *
7 | from profiles.views.scope import *
8 | from profiles.views.user import *
9 | from profiles.views.role import *
10 | from profiles.views.globalscope import *
11 | from profiles.views.quota import *
12 | from profiles.views.permission import *
13 |
--------------------------------------------------------------------------------
/service_catalog/api/serializers/service_serializers.py:
--------------------------------------------------------------------------------
1 | from rest_framework.serializers import ModelSerializer, ValidationError
2 |
3 | from service_catalog.models import Service
4 |
5 |
6 | class ServiceSerializer(ModelSerializer):
7 | class Meta:
8 | model = Service
9 | fields = '__all__'
10 |
11 | def validate_extra_vars(self, value):
12 | if value is None or not isinstance(value, dict):
13 | raise ValidationError("Please enter a valid JSON. Empty value is {} for JSON.")
14 | return value
15 |
--------------------------------------------------------------------------------
/service_catalog/management/commands/martor_cleanup.py:
--------------------------------------------------------------------------------
1 | import logging
2 |
3 | from django.core.management import BaseCommand
4 |
5 | from service_catalog.maintenance_jobs import cleanup_ghost_docs_images
6 |
7 | logger = logging.getLogger(__name__)
8 |
9 |
10 | class Command(BaseCommand):
11 |
12 | def __init__(self):
13 | super().__init__()
14 |
15 | def handle(self, *args, **options):
16 | print("[Cleanup Martor images] Start")
17 | cleanup_ghost_docs_images()
18 | print("[Cleanup Martor images] End")
19 |
--------------------------------------------------------------------------------
/docker/Caddyfile:
--------------------------------------------------------------------------------
1 | squest.domain.local { # This line should match the ALLOWED_HOSTS in your Squest settings
2 | reverse_proxy nginx:8080 maintenance:80 {
3 | # try to use django in first place. If not available we switch to maintenance
4 | lb_policy first
5 | lb_try_duration 5s
6 | fail_duration 30s
7 | }
8 | encode gzip zstd
9 | tls /etc/ssl/private/squest.crt /etc/ssl/private/squest.key
10 | # or:
11 | # tls /etc/ssl/private/cert.pem
12 |
13 | log {
14 | level error
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/service_catalog/api/serializers/operation_serializers.py:
--------------------------------------------------------------------------------
1 | from rest_framework.serializers import ModelSerializer, ValidationError
2 |
3 | from service_catalog.models import Operation
4 |
5 |
6 | class OperationSerializer(ModelSerializer):
7 | class Meta:
8 | model = Operation
9 | fields = '__all__'
10 |
11 | def validate_extra_vars(self, value):
12 | if value is None or not isinstance(value, dict):
13 | raise ValidationError("Please enter a valid JSON. Empty value is {} for JSON.")
14 | return value
15 |
--------------------------------------------------------------------------------
/service_catalog/tables/portfolio_tables.py:
--------------------------------------------------------------------------------
1 | from django_tables2 import TemplateColumn
2 |
3 | from Squest.utils.squest_table import SquestTable
4 | from service_catalog.models import Portfolio
5 |
6 |
7 | class PortfolioTable(SquestTable):
8 | actions = TemplateColumn(template_name='generics/custom_columns/generic_actions.html', orderable=False)
9 |
10 | class Meta:
11 | model = Portfolio
12 | attrs = {"id": "portfolio_table", "class": "table squest-pagination-tables"}
13 | fields = ("name", "description", "actions")
14 |
--------------------------------------------------------------------------------
/service_catalog/migrations/0007_service_external_support_url.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 3.2.12 on 2022-07-01 14:43
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [
9 | ('service_catalog', '0006_auto_20220630_1636'),
10 | ]
11 |
12 | operations = [
13 | migrations.AddField(
14 | model_name='service',
15 | name='external_support_url',
16 | field=models.CharField(blank=True, max_length=2000),
17 | ),
18 | ]
19 |
--------------------------------------------------------------------------------
/profiles/models/rbac.py:
--------------------------------------------------------------------------------
1 | from django.contrib.auth.models import Group
2 | from django.db.models import ForeignKey, CASCADE
3 |
4 | from profiles.models.role import Role
5 |
6 |
7 | class RBAC(Group):
8 | class Meta:
9 | unique_together = ('scope', 'role')
10 | default_permissions = ('add', 'change', 'delete', 'view', 'list')
11 |
12 | role = ForeignKey(Role, null=False, on_delete=CASCADE)
13 | scope = ForeignKey("AbstractScope", null=False, on_delete=CASCADE, related_name="rbac",
14 | related_query_name="rbac", )
15 |
--------------------------------------------------------------------------------
/profiles/migrations/0022_alter_permission_options.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 3.2.13 on 2023-10-18 13:53
2 |
3 | from django.db import migrations
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [
9 | ('profiles', '0021_create_default_permissions'),
10 | ]
11 |
12 | operations = [
13 | migrations.AlterModelOptions(
14 | name='permission',
15 | options={'default_permissions': ('add', 'change', 'delete', 'view', 'list'), 'ordering': ['content_type__model', 'codename']},
16 | ),
17 | ]
18 |
--------------------------------------------------------------------------------
/service_catalog/tables/email_template_table.py:
--------------------------------------------------------------------------------
1 | from django_tables2 import TemplateColumn, LinkColumn
2 |
3 | from Squest.utils.squest_table import SquestTable
4 | from service_catalog.models import EmailTemplate
5 |
6 |
7 | class EmailTemplateTable(SquestTable):
8 | name = LinkColumn()
9 | actions = TemplateColumn(template_name='generics/custom_columns/generic_actions.html', orderable=False)
10 |
11 | class Meta:
12 | model = EmailTemplate
13 | attrs = {"class": "table squest-pagination-tables "}
14 | fields = ("name", "actions")
15 |
--------------------------------------------------------------------------------
/service_catalog/templatetags/version.py:
--------------------------------------------------------------------------------
1 | from django import template
2 |
3 | register = template.Library()
4 |
5 |
6 | @register.simple_tag
7 | def commit_sha():
8 | """
9 | Return Squest 6 first characters of commit SHA.
10 | """
11 | from django.conf import settings
12 | return settings.SQUEST_COMMIT_SHA6
13 |
14 |
15 | @register.simple_tag
16 | def squest_version():
17 | """
18 | Return Squest version as listed in `__version__` in `init.py` of settings package
19 | """
20 | from Squest.version import __version__
21 | return __version__
22 |
--------------------------------------------------------------------------------
/templates/generics/table/table.html:
--------------------------------------------------------------------------------
1 | {% extends 'django_tables2/bootstrap4.html' %}
2 | {% block table %}
3 | {{ block.super }}
4 |
5 |
6 | {% if table.page %}
7 | Showing {{ table.page.start_index }}-{{ table.page.end_index }} of {{ table.page.paginator.count }}
8 | {% else %}
9 | {% if tables.rows|length != 0 %}
10 | Showing 1-{{ table.rows|length }} of {{ table.rows|length }}
11 | {% endif %}
12 | {% endif %}
13 |
14 | {% endblock table %}
15 |
--------------------------------------------------------------------------------
/resource_tracker_v2/templatetags/resource_filters.py:
--------------------------------------------------------------------------------
1 | from django.template.defaulttags import register
2 |
3 | from resource_tracker_v2.models import ResourceAttribute
4 |
5 |
6 | @register.filter(name='v2_get_attribute_value_from_name')
7 | def v2_get_attribute_value_from_name(resource, attribute_name):
8 | try:
9 | attribute = ResourceAttribute.objects.get(resource=resource,
10 | attribute_definition__name=attribute_name)
11 | return attribute.value
12 | except ResourceAttribute.DoesNotExist:
13 | return ""
14 |
--------------------------------------------------------------------------------
/service_catalog/migrations/0033_alter_approvalstepstate_options_and_more.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 4.2.6 on 2023-11-13 15:07
2 |
3 | from django.db import migrations, models
4 | import django.db.models.deletion
5 |
6 |
7 | class Migration(migrations.Migration):
8 |
9 | dependencies = [
10 | ('service_catalog', '0032_alter_operation_name_alter_operation_type'),
11 | ]
12 |
13 | operations = [
14 | migrations.AlterModelOptions(
15 | name='approvalstepstate',
16 | options={'ordering': ('approval_step__position',)},
17 | ),
18 | ]
19 |
--------------------------------------------------------------------------------
/profiles/api/views/role_api_views.py:
--------------------------------------------------------------------------------
1 | from Squest.utils.squest_api_views import SquestListCreateAPIView, SquestRetrieveUpdateDestroyAPIView
2 | from profiles.api.serializers import RoleSerializer
3 | from profiles.filters import RoleFilter
4 | from profiles.models import Role
5 |
6 |
7 | class RoleDetails(SquestRetrieveUpdateDestroyAPIView):
8 | serializer_class = RoleSerializer
9 | queryset = Role.objects.all()
10 |
11 |
12 | class RoleListCreate(SquestListCreateAPIView):
13 | serializer_class = RoleSerializer
14 | queryset = Role.objects.all()
15 | filterset_class = RoleFilter
16 |
--------------------------------------------------------------------------------
/profiles/api/views/team_api_views.py:
--------------------------------------------------------------------------------
1 | from Squest.utils.squest_api_views import SquestRetrieveUpdateDestroyAPIView, SquestListCreateAPIView
2 | from profiles.api.serializers import TeamSerializer
3 | from profiles.filters import TeamFilter
4 | from profiles.models import Team
5 |
6 |
7 | class TeamDetails(SquestRetrieveUpdateDestroyAPIView):
8 | serializer_class = TeamSerializer
9 | queryset = Team.objects.all()
10 |
11 |
12 | class TeamListCreate(SquestListCreateAPIView):
13 | serializer_class = TeamSerializer
14 | queryset = Team.objects.all()
15 | filterset_class = TeamFilter
16 |
--------------------------------------------------------------------------------
/profiles/api/views/globalscope_api_views.py:
--------------------------------------------------------------------------------
1 | from Squest.utils.squest_api_views import SquestRetrieveUpdateAPIView
2 | from profiles.api.serializers import GlobalScopeSerializer
3 | from profiles.models import GlobalScope
4 |
5 |
6 | class GlobalScopeDetails(SquestRetrieveUpdateAPIView):
7 | serializer_class = GlobalScopeSerializer
8 | queryset = GlobalScope.objects.all()
9 |
10 | def dispatch(self, request, *args, **kwargs):
11 | self.kwargs['pk'] = GlobalScope.load().id
12 | kwargs['pk'] = self.kwargs.get('pk')
13 | return super().dispatch(request, *args, **kwargs)
14 |
--------------------------------------------------------------------------------
/templates/generics/buttons/edit_button.html:
--------------------------------------------------------------------------------
1 | {% with app=object|to_app_name|lower %}
2 | {% with class=object|to_class_name|lower %}
3 | {% with perm=app|add:".change_"|add:class %}
4 | {% has_perm request.user perm object as can_change %}
5 | {% if can_change %}
6 |
8 |
9 |
10 | {% endif %}
11 | {% endwith %}
12 | {% endwith %}
13 | {% endwith %}
14 |
--------------------------------------------------------------------------------
/profiles/api/serializers/__init__.py:
--------------------------------------------------------------------------------
1 | from .contenttype_serializer import *
2 | from .permission_serializers import *
3 | from .request_notification_filter_serializer import *
4 | from .support_notification_filter_serializer import *
5 | from .request_notification_filter_serializer import *
6 | from .support_notification_filter_serializer import *
7 | from .role_serializer import *
8 | from .user_serializers import *
9 | from .rbac_serializers import *
10 | from .scope_serializer import *
11 | from .globalscope_serializer import *
12 | from .team_serializer import *
13 | from .organization_serializer import *
14 |
--------------------------------------------------------------------------------
/service_catalog/filters/doc_filter.py:
--------------------------------------------------------------------------------
1 | from django.forms import SelectMultiple
2 | from django_filters import ModelMultipleChoiceFilter
3 |
4 | from Squest.utils.squest_filter import SquestFilter
5 | from service_catalog.models import Doc, Service
6 |
7 |
8 | class ServiceFilter(ModelMultipleChoiceFilter):
9 |
10 | def __init__(self, *args, **kwargs):
11 | kwargs.setdefault('queryset', Service.objects.filter())
12 | super().__init__(label='Services', *args, **kwargs)
13 |
14 |
15 | class DocFilter(SquestFilter):
16 | class Meta:
17 | model = Doc
18 | fields = ['title']
19 |
--------------------------------------------------------------------------------
/k8s/squest_k8s/tasks/06-celery.yml:
--------------------------------------------------------------------------------
1 | - name: Deploy celery worker
2 | kubernetes.core.k8s:
3 | apply: true
4 | namespace: "{{ squest_namespace }}"
5 | definition: "{{ lookup('template', 'celery.deployment.yaml') | from_yaml }}"
6 | vars:
7 | celery_name: "celery-worker"
8 | celery_cmd_args: "worker"
9 |
10 | - name: Deploy celery beat
11 | kubernetes.core.k8s:
12 | apply: true
13 | namespace: "{{ squest_namespace }}"
14 | definition: "{{ lookup('template', 'celery.deployment.yaml') | from_yaml }}"
15 | vars:
16 | celery_name: "celery-beat"
17 | celery_cmd_args: "beat"
18 |
19 |
--------------------------------------------------------------------------------
/service_catalog/migrations/0020_alter_approvalstep_options.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 3.2.13 on 2023-08-16 16:00
2 |
3 | from django.db import migrations
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [
9 | ('service_catalog', '0019_auto_20230804_1516'),
10 | ]
11 |
12 | operations = [
13 | migrations.AlterModelOptions(
14 | name='approvalstep',
15 | options={'default_permissions': ('add', 'change', 'delete', 'view', 'list'), 'permissions': [('approve_reject_approvalstep', 'Can approve/reject an approval step')]},
16 | ),
17 | ]
18 |
--------------------------------------------------------------------------------
/service_catalog/tables/custom_link_table.py:
--------------------------------------------------------------------------------
1 | from django_tables2 import TemplateColumn
2 |
3 | from Squest.utils.squest_table import SquestTable
4 | from service_catalog.models import CustomLink
5 |
6 |
7 | class CustomLinkTable(SquestTable):
8 | actions = TemplateColumn(template_name='generics/custom_columns/generic_actions.html', orderable=False)
9 |
10 | class Meta:
11 | model = CustomLink
12 | attrs = {"id": "custom_link_table", "class": "table squest-pagination-tables "}
13 | fields = ("name", "actions")
14 |
15 | def render_name(self, record):
16 | return f"{record}"
17 |
--------------------------------------------------------------------------------
/templates/generics/buttons/delete_button.html:
--------------------------------------------------------------------------------
1 | {% with app=object|to_app_name|lower %}
2 | {% with class=object|to_class_name|lower %}
3 | {% with perm=app|add:".delete_"|add:class %}
4 | {% has_perm request.user perm object as can_delete %}
5 | {% if can_delete %}
6 |
8 |
9 |
10 | {% endif %}
11 | {% endwith %}
12 | {% endwith %}
13 | {% endwith %}
14 |
--------------------------------------------------------------------------------
/profiles/tables/instance_consumption_table.py:
--------------------------------------------------------------------------------
1 | from django_tables2 import LinkColumn
2 |
3 | from Squest.utils.squest_table import SquestTable
4 | from resource_tracker_v2.models import ResourceAttribute
5 |
6 |
7 | class InstanceConsumptionTable(SquestTable):
8 |
9 | resource__service_catalog_instance = LinkColumn(verbose_name="Instance")
10 |
11 | class Meta:
12 | model = ResourceAttribute
13 | attrs = {"id": "instance_consumption_table", "class": "table squest-pagination-tables"}
14 | fields = ("resource__service_catalog_instance", "resource__service_catalog_instance__requester", "value")
15 |
--------------------------------------------------------------------------------
/playbook_examples/test_get_api.yml:
--------------------------------------------------------------------------------
1 | # ansible-playbook playbook_examples/test_get_api.yml \
2 | # -i playbook_examples/squest_inventory/inventory
3 |
4 | ---
5 | - name: Get info from squest API
6 | hosts: squest_testing
7 | gather_facts: false
8 |
9 | tasks:
10 | - name: Get all resource group
11 | uri:
12 | url: "{{ squest_api }}/resource-tracker/resource-group/"
13 | headers:
14 | Authorization: "{{ squest_bearer_token }}"
15 | method: GET
16 | status_code: 200
17 | body_format: json
18 | register: output
19 |
20 | - debug:
21 | var: output
22 |
--------------------------------------------------------------------------------
/templates/service_catalog/buttons/instance_edit_button.html:
--------------------------------------------------------------------------------
1 |
2 | {% has_perm request.user "service_catalog.rename_instance" object as can_rename_instance %}
3 | {% has_perm request.user "service_catalog.change_instance" object as can_change_requester_instance %}
4 | {% has_perm request.user "service_catalog.change_owner_instance" object as can_change_instance %}
5 | {% if can_rename_instance or can_change_requester_instance or can_change_instance %}
6 |
8 |
9 |
10 | {% endif %}
11 |
--------------------------------------------------------------------------------
/tests/test_plugins/field_validators_test/superior_to_10.py:
--------------------------------------------------------------------------------
1 | from django.core.exceptions import ValidationError
2 | from rest_framework import serializers
3 | from django.utils.translation import gettext as _
4 |
5 |
6 | def validate_api(value):
7 | if int(value) < 10:
8 | raise serializers.ValidationError('Must be superior to 10')
9 |
10 |
11 | def validate_ui(value):
12 | try:
13 | if int(value) < 10:
14 | raise ValidationError(
15 | _('%(value)s not superior to 10'),
16 | params={'value': value},
17 | )
18 | except ValueError:
19 | pass
20 |
--------------------------------------------------------------------------------
/profiles/tables/permission_table.py:
--------------------------------------------------------------------------------
1 | from django_tables2 import TemplateColumn, Column
2 |
3 | from Squest.utils.squest_table import SquestTable
4 | from profiles.models.squest_permission import Permission
5 |
6 |
7 | class PermissionTable(SquestTable):
8 | actions = TemplateColumn(template_name='generics/custom_columns/generic_actions.html', orderable=False)
9 | content_type__model = Column(verbose_name="Model")
10 |
11 | class Meta:
12 | model = Permission
13 | attrs = {"id": "permission_table", "class": "table squest-pagination-tables"}
14 | fields = ("name", "codename", "content_type__model")
15 |
--------------------------------------------------------------------------------
/tests/setup/__init__.py:
--------------------------------------------------------------------------------
1 | from tests.setup.setup_org import SetupOrg, SetupOrgAPI, SetupOrgCommon
2 | from tests.setup.setup_team import SetupTeam, SetupTeamAPI, SetupTeamCommon
3 |
4 | from tests.setup.setup_awx import SetupDummyAWX, SetupDummyAWXAPI, SetupDummyAWXCommon
5 | from tests.setup.setup_service import SetupService, SetupServiceAPI, SetupServiceCommon
6 | from tests.setup.setup_operation import SetupOperation, SetupOperationAPI, SetupOperationCommon
7 | from tests.setup.setup_instance import SetupInstance, SetupInstanceAPI, SetupInstanceCommon
8 | from tests.setup.setup_request import SetupRequest, SetupRequestAPI, SetupRequestCommon
9 |
--------------------------------------------------------------------------------
/profiles/migrations/0019_alter_quota_options.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 3.2.13 on 2023-09-05 14:48
2 |
3 | from django.db import migrations
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [
9 | ('profiles', '0018_auto_20230803_1126'),
10 | ]
11 |
12 | operations = [
13 | migrations.AlterModelOptions(
14 | name='quota',
15 | options={'default_permissions': ('add', 'delete', 'view', 'list'), 'permissions': [('change_team_quota', 'Can change quota at team level'), ('change_organization_quota', 'Can change quota at organization level')]},
16 | ),
17 | ]
18 |
--------------------------------------------------------------------------------
/service_catalog/migrations/0010_doc_operations.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 3.2.13 on 2022-09-12 15:22
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [
9 | ('service_catalog', '0009_auto_20220804_1441'),
10 | ]
11 |
12 | operations = [
13 | migrations.AddField(
14 | model_name='doc',
15 | name='operations',
16 | field=models.ManyToManyField(blank=True, help_text='Operations linked to this doc.', related_name='docs', related_query_name='doc', to='service_catalog.Operation'),
17 | ),
18 | ]
19 |
--------------------------------------------------------------------------------
/profiles/api/views/user_api_views.py:
--------------------------------------------------------------------------------
1 | from django.contrib.auth.models import User
2 |
3 | from Squest.utils.squest_api_views import SquestRetrieveUpdateDestroyAPIView, SquestListCreateAPIView
4 | from profiles.api.serializers.user_serializers import UserSerializer
5 | from profiles.filters.user_filter import UserFilter
6 |
7 |
8 | class UserDetails(SquestRetrieveUpdateDestroyAPIView):
9 | serializer_class = UserSerializer
10 | queryset = User.objects.all()
11 |
12 |
13 | class UserListCreate(SquestListCreateAPIView):
14 | serializer_class = UserSerializer
15 | queryset = User.objects.all()
16 | filterset_class = UserFilter
17 |
--------------------------------------------------------------------------------
/service_catalog/forms/tower_server_update_token_forms.py:
--------------------------------------------------------------------------------
1 | from django import forms
2 |
3 | from Squest.utils.squest_model_form import SquestModelForm
4 | from service_catalog.models import TowerServer
5 |
6 |
7 | class TowerServerUpdateTokenForm(SquestModelForm):
8 | token = forms.CharField(label="Token",
9 | widget=forms.TextInput(),
10 | )
11 |
12 | def __init__(self, *args, **kwargs):
13 | super(TowerServerUpdateTokenForm, self).__init__(*args, **kwargs)
14 | self.initial['token'] = ""
15 |
16 |
17 | class Meta:
18 | model = TowerServer
19 | fields = ["token"]
20 |
--------------------------------------------------------------------------------
/resource_tracker_v2/tables/attribute_defintion_table.py:
--------------------------------------------------------------------------------
1 | from django_tables2 import TemplateColumn, LinkColumn
2 |
3 | from Squest.utils.squest_table import SquestTable
4 | from resource_tracker_v2.models import AttributeDefinition
5 |
6 |
7 | class AttributeDefinitionTable(SquestTable):
8 | class Meta:
9 | model = AttributeDefinition
10 | attrs = {"id": "attribute_definition_table", "class": "table squest-pagination-tables"}
11 | fields = ("name", "description", "actions")
12 |
13 | actions = TemplateColumn(template_name='generics/custom_columns/generic_actions.html', orderable=False)
14 | name = LinkColumn()
15 |
--------------------------------------------------------------------------------
/tests/test_plugins/field_validators_test/even_number.py:
--------------------------------------------------------------------------------
1 | from django.core.exceptions import ValidationError
2 | from rest_framework import serializers
3 | from django.utils.translation import gettext as _
4 |
5 |
6 | def validate_api(value):
7 | if int(value) % 2 != 0:
8 | raise serializers.ValidationError('This field must be an even number.')
9 |
10 |
11 | def validate_ui(value):
12 | try:
13 | if int(value) % 2 != 0:
14 | raise ValidationError(
15 | _('%(value)s is not an even number'),
16 | params={'value': value},
17 | )
18 | except ValueError:
19 | pass
20 |
--------------------------------------------------------------------------------
/profiles/forms/permission_form.py:
--------------------------------------------------------------------------------
1 | from Squest.utils.squest_model_form import SquestModelForm
2 | from profiles.models.squest_permission import Permission
3 |
4 |
5 | class PermissionForm(SquestModelForm):
6 | class Meta:
7 | model = Permission
8 | fields = "__all__"
9 |
10 | def __init__(self, *args, **kwargs):
11 | super().__init__(*args, **kwargs)
12 | self.fields['name'].help_text = f'A short description of the permission.'
13 | self.fields['codename'].help_text = f'Unique identifier of the permission in camel case format. ' \
14 | f'E.g: approve_custom_step'
15 |
--------------------------------------------------------------------------------
/service_catalog/celery.py:
--------------------------------------------------------------------------------
1 | import os
2 |
3 | from celery import Celery
4 |
5 | # set the default Django settings module for the 'celery' program.
6 | os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'Squest.settings')
7 |
8 | app = Celery('Squest')
9 |
10 | # Using a string here means the worker doesn't have to serialize
11 | # the configuration object to child processes.
12 | # - namespace='CELERY' means all celery-related configuration keys
13 | # should have a `CELERY_` prefix.
14 | app.config_from_object('django.conf:settings', namespace='CELERY')
15 |
16 | # Load task modules from all registered Django app configs.
17 | app.autodiscover_tasks()
18 |
--------------------------------------------------------------------------------
/service_catalog/migrations/0021_approvalstep_auto_accept_condition.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 3.2.13 on 2023-09-01 12:51
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [
9 | ('service_catalog', '0020_alter_approvalstep_options'),
10 | ]
11 |
12 | operations = [
13 | migrations.AddField(
14 | model_name='approvalstep',
15 | name='auto_accept_condition',
16 | field=models.TextField(blank=True, help_text="Ansible like 'when' with `request` as context. No Jinja brackets needed", null=True),
17 | ),
18 | ]
19 |
--------------------------------------------------------------------------------
/profiles/models/__init__.py:
--------------------------------------------------------------------------------
1 | from profiles.models.token import Token
2 | from profiles.models.role import Role
3 | from profiles.models.rbac import RBAC
4 | from profiles.models.organization import Organization
5 | from profiles.models.team import Team
6 | from profiles.models.profile import Profile
7 | from profiles.models.request_notification import RequestNotification
8 | from profiles.models.instance_notification import InstanceNotification
9 | from profiles.models.scope import AbstractScope, Scope
10 | from profiles.models.globalscope import GlobalScope
11 | from profiles.models.quota import Quota
12 | from profiles.models.squest_permission import Permission
13 |
--------------------------------------------------------------------------------
/service_catalog/migrations/0025_alter_approvalstep_auto_accept_condition.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 3.2.13 on 2023-09-14 13:33
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [
9 | ('service_catalog', '0024_alter_globalhook_state'),
10 | ]
11 |
12 | operations = [
13 | migrations.AlterField(
14 | model_name='approvalstep',
15 | name='auto_accept_condition',
16 | field=models.TextField(blank=True, default=None, help_text="Ansible like 'when' with `request` as context. No Jinja brackets needed", null=True),
17 | ),
18 | ]
19 |
--------------------------------------------------------------------------------
/service_catalog/views/login.py:
--------------------------------------------------------------------------------
1 | from django.contrib.auth import views as auth_views
2 |
3 |
4 | class LoginView(auth_views.LoginView):
5 | template_name = 'registration/login.html'
6 |
7 | def get_context_data(self, **kwargs):
8 | context = super().get_context_data(**kwargs)
9 | from django.conf import settings
10 | context.update({
11 | 'login_helper_text': settings.LOGIN_HELPER_TEXT,
12 | 'openid_active': settings.SOCIAL_AUTH_OIDC_ENABLED,
13 | 'openid_btn_text': settings.SOCIAL_AUTH_OIDC_BTN_TEXT,
14 | 'password_enabled': settings.PASSWORD_ENABLED
15 | })
16 | return context
17 |
--------------------------------------------------------------------------------
/tests/test_service_catalog/test_views/test_admin/test_tools/test_catalog/test_services/test_list.py:
--------------------------------------------------------------------------------
1 | from django.urls import reverse
2 |
3 | from service_catalog.models import Service
4 | from tests.test_service_catalog.base import BaseTest
5 |
6 |
7 | class ServiceListViewsTest(BaseTest):
8 |
9 | def setUp(self):
10 | super(ServiceListViewsTest, self).setUp()
11 | self.url = reverse('service_catalog:service_list')
12 |
13 | def test_get_list(self):
14 | response = self.client.get(self.url)
15 | self.assertEqual(200, response.status_code)
16 | self.assertEqual(len(response.context["table"].data.data), Service.objects.count())
17 |
--------------------------------------------------------------------------------
/profiles/api/views/permission_api_views.py:
--------------------------------------------------------------------------------
1 | from Squest.utils.squest_api_views import SquestRetrieveUpdateDestroyAPIView, SquestListCreateAPIView
2 | from profiles.api.serializers import PermissionSerializer
3 | from profiles.filters import PermissionFilter
4 | from profiles.models.squest_permission import Permission
5 |
6 |
7 | class PermissionDetails(SquestRetrieveUpdateDestroyAPIView):
8 | serializer_class = PermissionSerializer
9 | queryset = Permission.objects.all()
10 |
11 |
12 | class PermissionListCreate(SquestListCreateAPIView):
13 | serializer_class = PermissionSerializer
14 | queryset = Permission.objects.all()
15 | filterset_class = PermissionFilter
16 |
--------------------------------------------------------------------------------
/psql.docker-compose.yaml:
--------------------------------------------------------------------------------
1 |
2 | services:
3 | db:
4 | image: postgres:latest
5 | env_file: docker/environment_variables/db.env
6 | ports:
7 | - 5432:5432
8 | volumes:
9 | - db_data:/var/lib/postgresql/data
10 | - "./docker/scripts/psql-init.sh:/docker-entrypoint-initdb.d/db-init.sh"
11 |
12 | django:
13 | environment:
14 | WAIT_HOSTS: db:5432,rabbitmq:5672
15 |
16 | celery-worker:
17 | environment:
18 | WAIT_HOSTS: db:5432,rabbitmq:5672,django:8000
19 | WAIT_TIMEOUT: 60
20 |
21 | celery-beat:
22 | environment:
23 | WAIT_HOSTS: db:5432,rabbitmq:5672,django:8000
24 | WAIT_TIMEOUT: 60
--------------------------------------------------------------------------------
/service_catalog/api/views/job_template_api_views.py:
--------------------------------------------------------------------------------
1 | from Squest.utils.squest_api_views import SquestListAPIView, SquestRetrieveAPIView
2 | from service_catalog.api.serializers import JobTemplateSerializer
3 | from service_catalog.filters.job_template_filter import JobTemplateFilter
4 | from service_catalog.models import JobTemplate
5 |
6 |
7 | class JobTemplateDetails(SquestRetrieveAPIView):
8 | serializer_class = JobTemplateSerializer
9 | queryset = JobTemplate.objects.all()
10 |
11 |
12 | class JobTemplateList(SquestListAPIView):
13 | serializer_class = JobTemplateSerializer
14 | filterset_class = JobTemplateFilter
15 | queryset = JobTemplate.objects.all()
16 |
--------------------------------------------------------------------------------
/Squest/utils/squest_table.py:
--------------------------------------------------------------------------------
1 | from django_tables2 import tables, RequestConfig
2 |
3 |
4 | class SquestTable(tables.Table):
5 |
6 | def __init__(self, *args, **kwargs):
7 | hide_field = list()
8 | if 'hide_fields' in kwargs:
9 | hide_field = kwargs.pop("hide_fields")
10 | super(SquestTable, self).__init__(*args, **kwargs)
11 |
12 | for field in hide_field:
13 | if field in self.columns.columns:
14 | self.columns.hide(field)
15 |
16 |
17 | class SquestRequestConfig(RequestConfig):
18 |
19 | def __init__(self, request, paginate=False):
20 | self.request = request
21 | self.paginate = paginate
22 |
--------------------------------------------------------------------------------
/monitoring/apps.py:
--------------------------------------------------------------------------------
1 | import sys
2 |
3 | from django.apps import AppConfig
4 | import prometheus_client
5 | from django.db.models.signals import post_migrate
6 |
7 |
8 | def run_prometheus_metrics(sender, **kwargs):
9 | from .models import ComponentCollector
10 | prometheus_client.REGISTRY.register(ComponentCollector())
11 |
12 |
13 | class MonitoringConfig(AppConfig):
14 | default_auto_field = 'django.db.models.BigAutoField'
15 | name = 'monitoring'
16 |
17 | def ready(self):
18 | banned_words = ['test']
19 | if not any(banned_word in sys.argv for banned_word in banned_words):
20 | post_migrate.connect(run_prometheus_metrics, sender=self)
21 |
--------------------------------------------------------------------------------
/profiles/api/views/organization_api_views.py:
--------------------------------------------------------------------------------
1 | from Squest.utils.squest_api_views import SquestListCreateAPIView, SquestRetrieveUpdateDestroyAPIView
2 | from profiles.api.serializers import OrganizationSerializer
3 | from profiles.filters import OrganizationFilter
4 | from profiles.models import Organization
5 |
6 |
7 | class OrganizationDetails(SquestRetrieveUpdateDestroyAPIView):
8 | serializer_class = OrganizationSerializer
9 | queryset = Organization.objects.all()
10 |
11 |
12 | class OrganizationListCreate(SquestListCreateAPIView):
13 | serializer_class = OrganizationSerializer
14 | queryset = Organization.objects.all()
15 | filterset_class = OrganizationFilter
16 |
--------------------------------------------------------------------------------
/plugins/field_validators/is_json.py:
--------------------------------------------------------------------------------
1 | import json
2 |
3 | # For testing
4 | try:
5 | from django.core.exceptions import ValidationError as UIValidationError
6 | from rest_framework.serializers import ValidationError as APIValidationError
7 | except ImportError:
8 | pass
9 |
10 |
11 | def is_json(json_str):
12 | try:
13 | json.loads(json_str)
14 | except ValueError as e:
15 | return False
16 | return True
17 |
18 |
19 | def validate_api(value):
20 | if not is_json(value):
21 | raise APIValidationError("is not JSON")
22 |
23 |
24 | def validate_ui(value):
25 | if not is_json(value):
26 | raise UIValidationError("is not JSON")
27 |
--------------------------------------------------------------------------------
/service_catalog/api/serializers/request_message_serializer.py:
--------------------------------------------------------------------------------
1 | from rest_framework.serializers import ModelSerializer, Serializer, CharField
2 |
3 | from service_catalog.models import RequestMessage
4 |
5 |
6 | class MessageSerializer(Serializer):
7 | content = CharField(
8 | label="Message",
9 | help_text="Message attached to this request"
10 | )
11 |
12 |
13 | class RequestMessageReadSerializer(ModelSerializer):
14 | class Meta:
15 | model = RequestMessage
16 | fields = '__all__'
17 |
18 |
19 | class RequestMessageSerializer(ModelSerializer):
20 | class Meta:
21 | model = RequestMessage
22 | fields = ('sender', 'request', 'content')
23 |
--------------------------------------------------------------------------------
/service_catalog/views/__init__.py:
--------------------------------------------------------------------------------
1 | from .login import *
2 | from .common import *
3 | from .portfolio import *
4 | from .request import *
5 | from .service import *
6 | from .instance import *
7 | from .catalog_views import *
8 | from .filters import *
9 | from .announcement import *
10 | from .custom_link import *
11 | from .request import *
12 | from .mail_test import *
13 | from .operation import *
14 | from .support import *
15 | from .doc import *
16 | from .tower_server import *
17 | from .job_template import *
18 | from .global_hook import *
19 | from .tower_survey_field import *
20 | from .approval_step_views import *
21 | from .approval_workflow_views import *
22 | from .email_template import *
23 |
--------------------------------------------------------------------------------
/service_catalog/migrations/0043_operation_when.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 4.2.13 on 2024-11-15 08:27
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [
9 | ('service_catalog', '0042_alter_instance_options'),
10 | ]
11 |
12 | operations = [
13 | migrations.AddField(
14 | model_name='operation',
15 | name='when',
16 | field=models.CharField(blank=True, help_text="Ansible like 'when' with `instance` as context. No Jinja brackets needed. Cannot be set on 'create' type of operation as the instance does not exist yet", max_length=2000, null=True),
17 | ),
18 | ]
19 |
--------------------------------------------------------------------------------
/templates/404.html:
--------------------------------------------------------------------------------
1 | {% extends "base.html" %}
2 |
3 | {% block content %}
4 |
5 |
7 |
8 |
9 |
404
10 |
11 |
Not Found
12 |
The requested resource was not found on this server.
13 |
14 |
15 |
16 |
17 |
18 | {% endblock %}
19 |
--------------------------------------------------------------------------------
/templates/service_catalog/mails/utils/header.html:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
8 |
9 |
11 | {{ title }}
12 |
13 | |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/ldap.docker-compose.yml:
--------------------------------------------------------------------------------
1 | # docker-compose -f docker-compose.yml -f docker-compose.override.yml -f tls.docker-compose.yml -f ldap.docker-compose.yml up
2 | services:
3 |
4 | django:
5 | volumes:
6 | - ./Squest/ldap_config.py:/app/Squest/ldap_config.py
7 | - ./docker/certs/ldap_ca.crt:/usr/local/share/ca-certificates/ldap_ca.crt
8 | celery-worker:
9 | volumes:
10 | - ./Squest/ldap_config.py:/app/Squest/ldap_config.py
11 | - ./docker/certs/ldap_ca.crt:/usr/local/share/ca-certificates/ldap_ca.crt
12 | celery-beat:
13 | volumes:
14 | - ./Squest/ldap_config.py:/app/Squest/ldap_config.py
15 | - ./docker/certs/ldap_ca.crt:/usr/local/share/ca-certificates/ldap_ca.crt
16 |
--------------------------------------------------------------------------------
/service_catalog/migrations/0034_alter_request_approval_workflow_state.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 4.2.6 on 2023-11-14 13:27
2 |
3 | from django.db import migrations, models
4 | import django.db.models.deletion
5 |
6 |
7 | class Migration(migrations.Migration):
8 |
9 | dependencies = [
10 | ('service_catalog', '0033_alter_approvalstepstate_options_and_more'),
11 | ]
12 |
13 | operations = [
14 | migrations.AlterField(
15 | model_name='request',
16 | name='approval_workflow_state',
17 | field=models.OneToOneField(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='service_catalog.approvalworkflowstate'),
18 | ),
19 | ]
20 |
--------------------------------------------------------------------------------
/resource_tracker_v2/api/views/resource_api_view.py:
--------------------------------------------------------------------------------
1 | from Squest.utils.squest_api_views import SquestListCreateAPIView, SquestRetrieveUpdateDestroyAPIView
2 | from resource_tracker_v2.api.serializers.resource_serializer import ResourceSerializer
3 | from resource_tracker_v2.filters.resource_filter import ResourceFilter
4 | from resource_tracker_v2.models import Resource
5 |
6 |
7 | class ResourceListCreate(SquestListCreateAPIView):
8 | serializer_class = ResourceSerializer
9 | filterset_class = ResourceFilter
10 | queryset = Resource.objects.all()
11 |
12 |
13 | class ResourceDetails(SquestRetrieveUpdateDestroyAPIView):
14 | serializer_class = ResourceSerializer
15 | queryset = Resource.objects.all()
16 |
--------------------------------------------------------------------------------
/tests/test_service_catalog/test_api/test_instance/test_user_spec/test_user_spec_put.py:
--------------------------------------------------------------------------------
1 | from rest_framework.reverse import reverse
2 |
3 | from tests.test_service_catalog.test_api.test_instance.test_spec.test_spec_put import TestApiSpecPut
4 |
5 |
6 | class TestApiUserSpecPut(TestApiSpecPut):
7 |
8 | def setUp(self):
9 | super(TestApiUserSpecPut, self).setUp()
10 | self.target_spec = "user-spec"
11 | self.get_spec_details_url = reverse('api_instance_user_spec_details', kwargs=self.kwargs)
12 |
13 | def test_admin_put_user_spec(self):
14 | self.test_admin_put_spec()
15 |
16 | def test_cannot_put_user_spec_when_logout(self):
17 | self.test_cannot_put_spec_when_logout()
18 |
--------------------------------------------------------------------------------
/resource_tracker_v2/forms/resource_group_form.py:
--------------------------------------------------------------------------------
1 | from django import forms
2 | from taggit.forms import TagField, TagWidget
3 |
4 | from Squest.utils.squest_model_form import SquestModelForm
5 | from resource_tracker_v2.models import ResourceGroup
6 |
7 |
8 | class ResourceGroupForm(SquestModelForm):
9 | class Meta:
10 | model = ResourceGroup
11 | fields = ["name", "tags"]
12 |
13 | name = forms.CharField(label="Name",
14 | widget=forms.TextInput())
15 |
16 | tags = TagField(label="Tags",
17 | required=False,
18 | help_text="Comma-separated list of tags (more details in documentation)",
19 | widget=TagWidget())
20 |
--------------------------------------------------------------------------------
/service_catalog/api/views/portfolio_api_views.py:
--------------------------------------------------------------------------------
1 | from Squest.utils.squest_api_views import SquestRetrieveUpdateDestroyAPIView, SquestListCreateAPIView
2 | from service_catalog.api.serializers.portfolio_serializer import PortfolioSerializer
3 | from service_catalog.filters.portfolio_filter import PortfolioFilter
4 | from service_catalog.models.portfolio import Portfolio
5 |
6 |
7 | class PortfolioDetails(SquestRetrieveUpdateDestroyAPIView):
8 | queryset = Portfolio.objects.all()
9 | serializer_class = PortfolioSerializer
10 |
11 |
12 | class PortfolioListCreate(SquestListCreateAPIView):
13 | filterset_class = PortfolioFilter
14 | serializer_class = PortfolioSerializer
15 | queryset = Portfolio.objects.all()
16 |
--------------------------------------------------------------------------------
/service_catalog/models/inventory.py:
--------------------------------------------------------------------------------
1 | from django.db.models import CharField, IntegerField, ForeignKey, CASCADE
2 |
3 | from Squest.utils.squest_model import SquestModel
4 | from service_catalog.models import TowerServer
5 |
6 |
7 | class Inventory(SquestModel):
8 | class Meta:
9 | unique_together = ('tower_id', 'tower_server',)
10 | default_permissions = ('add', 'change', 'delete', 'view', 'list')
11 |
12 | name = CharField(max_length=100)
13 | tower_id = IntegerField()
14 | tower_server = ForeignKey(TowerServer,
15 | on_delete=CASCADE,
16 | related_name="inventories",
17 | related_query_name="inventory")
18 |
--------------------------------------------------------------------------------
/tests/test_service_catalog/test_models/test_doc.py:
--------------------------------------------------------------------------------
1 | from service_catalog.models import Doc
2 | from tests.setup import SetupInstance
3 |
4 |
5 | class TestDoc(SetupInstance):
6 |
7 | def test_render(self):
8 | # no instance, render return content
9 | new_doc = Doc.objects.create(title="test", content="test")
10 | self.assertEqual(new_doc.render(), "test")
11 |
12 | # with an instance with use the templating
13 | self.instance_1_org1.spec["dns"] = "name.domain.local"
14 | self.instance_1_org1.save()
15 | new_doc.content = "test {{ instance.spec.dns }}"
16 | new_doc.save()
17 | self.assertEqual(new_doc.render(self.instance_1_org1), "test name.domain.local")
18 |
--------------------------------------------------------------------------------
/docs/index.md:
--------------------------------------------------------------------------------
1 | # Squest
2 |
3 |
4 |
5 |
6 |
7 | # Welcome to the Squest documentation!
8 |
9 | Squest is a self-service portal that works on top of Red Hat Ansible Automation Platform/AWX.
10 |
11 | - Follow the [installation guide](getting_started.md) to get your own deployment up and running
12 | - Discuss with developers or the community on [Gitter Chat](https://app.gitter.im/#/room/#HewlettPackard_squest:gitter.im)
13 | - Check out our [GitHub repository](https://github.com/HewlettPackard/squest) if you are interested into contributing to Squest
14 | - Don't hesitate to [raise an issue](https://github.com/HewlettPackard/squest/issues) to propose new features or raise a bug
15 |
--------------------------------------------------------------------------------
/profiles/migrations/0007_auto_20221005_1107.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 3.2.13 on 2022-10-05 09:07
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [
9 | ('profiles', '0006_auto_20220804_1441'),
10 | ]
11 |
12 | operations = [
13 | migrations.RemoveField(
14 | model_name='notificationfilter',
15 | name='instance_states',
16 | ),
17 | migrations.AlterField(
18 | model_name='notificationfilter',
19 | name='when',
20 | field=models.TextField(blank=True, help_text="Ansible like 'when' with `request` as context. No Jinja brackets needed", null=True),
21 | ),
22 | ]
23 |
--------------------------------------------------------------------------------
/service_catalog/api/views/custom_link_api_views.py:
--------------------------------------------------------------------------------
1 | from Squest.utils.squest_api_views import SquestRetrieveUpdateDestroyAPIView, SquestListCreateAPIView
2 | from service_catalog.api.serializers.custom_link_serializer import CustomLinkSerializer
3 | from service_catalog.filters.custom_link_filter import CustomLinkFilter
4 | from service_catalog.models.custom_link import CustomLink
5 |
6 |
7 | class CustomLinkDetails(SquestRetrieveUpdateDestroyAPIView):
8 | queryset = CustomLink.objects.all()
9 | serializer_class = CustomLinkSerializer
10 |
11 |
12 | class CustomLinkListCreate(SquestListCreateAPIView):
13 | filterset_class = CustomLinkFilter
14 | serializer_class = CustomLinkSerializer
15 | queryset = CustomLink.objects.all()
16 |
--------------------------------------------------------------------------------
/service_catalog/tables/support_tables.py:
--------------------------------------------------------------------------------
1 | from django_tables2 import TemplateColumn, LinkColumn
2 |
3 | from Squest.utils.squest_table import SquestTable
4 | from service_catalog.models import Support
5 |
6 |
7 | class SupportTable(SquestTable):
8 | state = TemplateColumn(template_name='service_catalog/custom_columns/support_state.html')
9 | date_opened = TemplateColumn(template_name='generics/custom_columns/generic_date_format.html')
10 | title = LinkColumn()
11 | instance = LinkColumn()
12 |
13 | class Meta:
14 | model = Support
15 | attrs = {"id": "support_table", "class": "table squest-pagination-tables"}
16 | fields = ("title", "instance", "instance__service", "opened_by", "date_opened", "state")
17 |
--------------------------------------------------------------------------------
/tests/setup/setup_org.py:
--------------------------------------------------------------------------------
1 | from django.test import TestCase
2 | from django.test.testcases import TransactionTestCase
3 | from rest_framework.test import APITestCase
4 |
5 | from profiles.models import Organization
6 |
7 |
8 | class SetupOrgCommon(TransactionTestCase):
9 |
10 | def setUp(self):
11 | # Organization
12 | self.org1 = Organization.objects.create(name='Organization 1')
13 | self.org2 = Organization.objects.create(name='Organization 2')
14 | self.org3 = Organization.objects.create(name='Organization 3')
15 |
16 | print("SetupOrgCommon finished")
17 |
18 | class SetupOrg(TestCase, SetupOrgCommon):
19 | pass
20 |
21 |
22 | class SetupOrgAPI(APITestCase, SetupOrgCommon):
23 | pass
24 |
--------------------------------------------------------------------------------
/profiles/models/notification_filter.py:
--------------------------------------------------------------------------------
1 | from django.db.models import ManyToManyField, TextField, CharField
2 |
3 | from Squest.utils.squest_model import SquestModel
4 |
5 |
6 | class NotificationFilter(SquestModel):
7 | class Meta:
8 | abstract = True
9 |
10 | name = CharField(max_length=100)
11 | services = ManyToManyField(
12 | "service_catalog.Service",
13 | blank=True,
14 | )
15 | # "E.G: request.instance.spec['configvar'] == 'value' and request.fill_in_survey['location'] == 'value'"
16 | when = TextField(blank=True, null=True,
17 | help_text="Ansible like 'when' with `request` as context. No Jinja brackets needed")
18 |
19 | def __str__(self):
20 | return self.name
21 |
--------------------------------------------------------------------------------
/manage.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | """Django's command-line utility for administrative tasks."""
3 | import os
4 | import sys
5 |
6 |
7 | def main():
8 | """Run administrative tasks."""
9 | os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'Squest.settings')
10 | try:
11 | from django.core.management import execute_from_command_line
12 | except ImportError as exc:
13 | raise ImportError(
14 | "Couldn't import Django. Are you sure it's installed and "
15 | "available on your PYTHONPATH environment variable? Did you "
16 | "forget to activate a virtual environment?"
17 | ) from exc
18 | execute_from_command_line(sys.argv)
19 |
20 |
21 | if __name__ == '__main__':
22 | main()
23 |
--------------------------------------------------------------------------------
/profiles/models/squest_permission.py:
--------------------------------------------------------------------------------
1 | from django.contrib.auth.models import Permission
2 | from django.urls import reverse
3 |
4 | from Squest.utils.squest_model import SquestRBAC, SquestDeleteCascadeMixIn
5 |
6 |
7 | class Permission(SquestRBAC, Permission, SquestDeleteCascadeMixIn):
8 | class Meta:
9 | proxy = True
10 | default_permissions = ('add', 'change', 'delete', 'view', 'list')
11 | ordering = ["content_type__model", "codename"]
12 |
13 | @property
14 | def permission_str(self):
15 | return f"{self.content_type.app_label}.{self.codename}"
16 |
17 | def get_absolute_url(self):
18 | return reverse(f"profiles:permission_list")
19 |
20 | def __str__(self):
21 | return self.codename
22 |
--------------------------------------------------------------------------------
/resource_tracker_v2/api/views/transformer_api_views.py:
--------------------------------------------------------------------------------
1 | from Squest.utils.squest_api_views import SquestRetrieveUpdateDestroyAPIView, SquestListCreateAPIView
2 | from resource_tracker_v2.api.serializers.transformer_serializer import TransformerSerializer
3 | from resource_tracker_v2.filters.transformer_filter import TransformerFilter
4 | from resource_tracker_v2.models import Transformer
5 |
6 |
7 | class TransformerListCreate(SquestListCreateAPIView):
8 | serializer_class = TransformerSerializer
9 | filterset_class = TransformerFilter
10 | queryset = Transformer.objects.all()
11 |
12 |
13 | class TransformerDetails(SquestRetrieveUpdateDestroyAPIView):
14 | serializer_class = TransformerSerializer
15 | queryset = Transformer.objects.all()
16 |
--------------------------------------------------------------------------------
/service_catalog/api/views/approval_step_api_views.py:
--------------------------------------------------------------------------------
1 | from Squest.utils.squest_api_views import SquestListCreateAPIView, SquestRetrieveUpdateDestroyAPIView
2 | from service_catalog.api.serializers.approval_step_serializer import ApprovalStepSerializer
3 | from service_catalog.filters.approval_step_filter import ApprovalStepFilter
4 | from service_catalog.models import ApprovalStep
5 |
6 |
7 | class ApprovalStepListCreate(SquestListCreateAPIView):
8 | serializer_class = ApprovalStepSerializer
9 | filterset_class = ApprovalStepFilter
10 | queryset = ApprovalStep.objects.all()
11 |
12 |
13 | class ApprovalStepDetails(SquestRetrieveUpdateDestroyAPIView):
14 | serializer_class = ApprovalStepSerializer
15 | queryset = ApprovalStep.objects.all()
16 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/bug_report.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Bug report
3 | about: Create a report to help us improve
4 | title: ''
5 | labels: ''
6 | assignees: ''
7 |
8 | ---
9 |
10 | **Describe the bug**
11 | A clear and concise description of what the bug is.
12 |
13 | **To Reproduce**
14 | Steps to reproduce the behavior:
15 | 1. Go to '...'
16 | 2. Click on '....'
17 | 3. Scroll down to '....'
18 | 4. See error
19 |
20 | **Expected behavior**
21 | A clear and concise description of what you expected to happen.
22 |
23 | **Screenshots**
24 | If applicable, add screenshots to help explain your problem.
25 |
26 | **Additional context**
27 | Add any other context about the problem here.
28 |
29 | - Squest version or GIT commit number:
30 | - Ansible Tower/AWX version:
31 |
--------------------------------------------------------------------------------
/service_catalog/migrations/0031_service_attribute_definitions.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 4.2.6 on 2023-11-15 15:58
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [
9 | ('resource_tracker_v2', '0005_auto_20230803_1126'),
10 | ('service_catalog', '0030_emailtemplate'),
11 | ]
12 |
13 | operations = [
14 | migrations.AddField(
15 | model_name='service',
16 | name='attribute_definitions',
17 | field=models.ManyToManyField(blank=True, help_text='List of attributes linked to the service, they could be used on operation fields.', related_name='services', to='resource_tracker_v2.attributedefinition'),
18 | ),
19 | ]
20 |
--------------------------------------------------------------------------------
/service_catalog/models/credential.py:
--------------------------------------------------------------------------------
1 | from django.db.models import CharField, IntegerField, ForeignKey, CASCADE
2 |
3 | from Squest.utils.squest_model import SquestModel
4 | from service_catalog.models import TowerServer
5 |
6 |
7 | class Credential(SquestModel):
8 | class Meta:
9 | unique_together = ('tower_id', 'tower_server',)
10 | default_permissions = ('add', 'change', 'delete', 'view', 'list')
11 |
12 | name = CharField(max_length=100)
13 | tower_id = IntegerField()
14 | tower_server = ForeignKey(TowerServer,
15 | on_delete=CASCADE,
16 | related_name="credentials",
17 | related_query_name="credential"
18 | )
19 |
--------------------------------------------------------------------------------
/profiles/tables/approval_workflow.py:
--------------------------------------------------------------------------------
1 | from django.utils.html import format_html
2 | from django_tables2 import LinkColumn, TemplateColumn
3 |
4 | from Squest.utils.squest_table import SquestTable
5 | from profiles.models import Scope
6 |
7 |
8 | class ApprovalWorkflowPreviewTable(SquestTable):
9 |
10 | name = LinkColumn()
11 | preview = TemplateColumn(template_name='profiles/custom_columns/preview_workflow.html', orderable=False)
12 |
13 | class Meta:
14 | model = Scope
15 | attrs = {"id": "role_table", "class": "table squest-pagination-tables"}
16 | fields = ("name", "preview")
17 |
18 | def render_name(self, value, record):
19 | return format_html(f'{record}')
20 |
--------------------------------------------------------------------------------
/profiles/migrations/0002_auto_20211105_0946.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 3.2.7 on 2021-11-05 08:46
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [
9 | ('service_catalog', '0001_initial'),
10 | ('profiles', '0001_initial'),
11 | ]
12 |
13 | operations = [
14 | migrations.AddField(
15 | model_name='profile',
16 | name='notification_enabled',
17 | field=models.BooleanField(default=True),
18 | ),
19 | migrations.AddField(
20 | model_name='profile',
21 | name='subscribed_services_notification',
22 | field=models.ManyToManyField(to='service_catalog.Service'),
23 | ),
24 | ]
25 |
--------------------------------------------------------------------------------
/tests/setup/setup_team.py:
--------------------------------------------------------------------------------
1 | from django.test import TestCase
2 | from rest_framework.test import APITestCase
3 |
4 | from profiles.models import Team
5 | from tests.setup import SetupOrgCommon
6 |
7 |
8 | class SetupTeamCommon(SetupOrgCommon):
9 |
10 | def setUp(self):
11 | super().setUp()
12 | # Team
13 | self.team1org2 = Team.objects.create(name='Org2 - Team 1', org=self.org2)
14 | self.team2org2 = Team.objects.create(name='Org2 - Team 2', org=self.org2)
15 | self.team1org3 = Team.objects.create(name='Org3 - Team 1', org=self.org3)
16 | print("SetupTeamCommon finished")
17 |
18 |
19 | class SetupTeam(TestCase, SetupTeamCommon):
20 | pass
21 |
22 |
23 | class SetupTeamAPI(APITestCase, SetupTeamCommon):
24 | pass
25 |
--------------------------------------------------------------------------------
/templates/500.html:
--------------------------------------------------------------------------------
1 | {% extends "base.html" %}
2 |
3 | {% block content %}
4 |
5 |
7 |
8 |
9 |
500
10 |
11 |
Oops! Something went wrong.
12 |
We will work on fixing that right away. Meanwhile, you may return to homepage
13 |
14 |
15 |
16 |
17 |
18 | {% endblock %}
19 |
--------------------------------------------------------------------------------
/tests/setup/setup_service.py:
--------------------------------------------------------------------------------
1 | from django.test import TestCase
2 | from rest_framework.test import APITestCase
3 |
4 | from service_catalog.models import Service
5 | from tests.setup import SetupDummyAWXCommon
6 |
7 |
8 | class SetupServiceCommon(SetupDummyAWXCommon):
9 |
10 | def setUp(self):
11 | super().setUp()
12 | # Team
13 | self.service_1 = Service.objects.create(name="Service 1", description="Description of service 1")
14 | self.service_2 = Service.objects.create(name="Service 2", description="Description of service 2")
15 |
16 | print("SetupServiceCommon finished")
17 |
18 | class SetupService(TestCase, SetupServiceCommon):
19 | pass
20 |
21 |
22 | class SetupServiceAPI(APITestCase, SetupServiceCommon):
23 | pass
24 |
--------------------------------------------------------------------------------
/resource_tracker_v2/api/views/resource_group_api_views.py:
--------------------------------------------------------------------------------
1 | from Squest.utils.squest_api_views import SquestListCreateAPIView, SquestRetrieveUpdateDestroyAPIView
2 | from resource_tracker_v2.api.serializers.resource_group_serializers import ResourceGroupSerializer
3 | from resource_tracker_v2.filters.resource_group_filter import ResourceGroupFilter
4 | from resource_tracker_v2.models import ResourceGroup
5 |
6 |
7 | class ResourceGroupList(SquestListCreateAPIView):
8 | queryset = ResourceGroup.objects.all()
9 | serializer_class = ResourceGroupSerializer
10 | filterset_class = ResourceGroupFilter
11 |
12 |
13 | class ResourceGroupDetails(SquestRetrieveUpdateDestroyAPIView):
14 | queryset = ResourceGroup.objects.all()
15 | serializer_class = ResourceGroupSerializer
16 |
--------------------------------------------------------------------------------
/resource_tracker_v2/models/resource_group.py:
--------------------------------------------------------------------------------
1 | from django.db.models import CharField
2 | from django.urls import reverse
3 | from taggit.managers import TaggableManager
4 |
5 | from Squest.utils.squest_model import SquestModel
6 |
7 |
8 | class ResourceGroup(SquestModel):
9 |
10 | name = CharField(max_length=100,
11 | blank=False,
12 | unique=True)
13 |
14 | tags = TaggableManager()
15 |
16 | def __str__(self):
17 | return self.name
18 |
19 | def create_resource(self, name):
20 | resource, _ = self.resources.get_or_create(name=name, resource_group=self)
21 | return resource
22 |
23 | def get_absolute_url(self):
24 | return reverse("resource_tracker_v2:resourcegroup_details",args=[self.pk])
25 |
--------------------------------------------------------------------------------
/service_catalog/admin.py:
--------------------------------------------------------------------------------
1 | from django.contrib import admin
2 | from django.db import models
3 | from martor.widgets import AdminMartorWidget
4 |
5 | from service_catalog.models.documentation import Doc
6 |
7 |
8 | class DocAdmin(admin.ModelAdmin):
9 | formfield_overrides = {
10 | models.TextField: {'widget': AdminMartorWidget},
11 | }
12 |
13 | list_filter = ['services', 'operations']
14 | list_display = ['title', 'linked_services', 'linked_operations']
15 |
16 | def linked_services(self, obj):
17 | return ", ".join([str(service) for service in obj.services.all()])
18 |
19 | def linked_operations(self, obj):
20 | return ", ".join([str(operation) for operation in obj.operations.all()])
21 |
22 |
23 | admin.site.register(Doc, DocAdmin)
24 |
--------------------------------------------------------------------------------
/templates/service_catalog/custom_columns/tower_server_actions.html:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/tests/test_service_catalog/test_api/test_instance/test_user_spec/test_user_spec_patch.py:
--------------------------------------------------------------------------------
1 | from rest_framework.reverse import reverse
2 |
3 | from tests.test_service_catalog.test_api.test_instance.test_spec.test_spec_patch import TestApiSpecPatch
4 |
5 |
6 | class TestApiUserSpecPatch(TestApiSpecPatch):
7 |
8 | def setUp(self):
9 | super(TestApiUserSpecPatch, self).setUp()
10 | self.get_spec_details_url = reverse('api_instance_user_spec_details', kwargs=self.kwargs)
11 | self.target_spec = "user-spec"
12 | self.expected_data = self.expected_user_spec
13 |
14 | def test_admin_patch_user_spec(self):
15 | self.test_admin_patch_spec()
16 |
17 | def test_cannot_patch_user_spec_when_logout(self):
18 | self.test_cannot_patch_spec_when_logout()
19 |
--------------------------------------------------------------------------------
/profiles/filters/user_filter.py:
--------------------------------------------------------------------------------
1 | import django_filters
2 | from django import forms
3 | from django.contrib.auth.models import User
4 |
5 | from Squest.utils.squest_filter import SquestFilter
6 |
7 |
8 | class UserFilter(SquestFilter):
9 | class Meta:
10 | model = User
11 | fields = ['username', 'email']
12 |
13 | no_organization = django_filters.BooleanFilter(method='has_no_organization',
14 | label="No organization",
15 | widget=forms.CheckboxInput(attrs={'class': 'form-control-checkbox'}))
16 |
17 | def has_no_organization(self, queryset, field_name, value):
18 | if not value:
19 | return queryset
20 | return queryset.filter(groups__isnull=True)
21 |
--------------------------------------------------------------------------------
/service_catalog/migrations/0029_alter_instance_requester.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 4.2.6 on 2023-10-26 14:10
2 |
3 | from django.conf import settings
4 | from django.db import migrations, models
5 | import django.db.models.deletion
6 |
7 |
8 | class Migration(migrations.Migration):
9 |
10 | dependencies = [
11 | migrations.swappable_dependency(settings.AUTH_USER_MODEL),
12 | ('service_catalog', '0028_set_last_update_on_request'),
13 | ]
14 |
15 | operations = [
16 | migrations.AlterField(
17 | model_name='instance',
18 | name='requester',
19 | field=models.ForeignKey(help_text='Initial requester', null=True, on_delete=django.db.models.deletion.PROTECT, to=settings.AUTH_USER_MODEL, verbose_name='Owner'),
20 | ),
21 | ]
22 |
--------------------------------------------------------------------------------
/templates/generics/generic_form.html:
--------------------------------------------------------------------------------
1 | {% extends 'base.html' %}
2 | {% block main %}
3 |
4 |
5 | {% if form_header %}{% include form_header %}{% endif %}
6 |
7 |
8 | {% include "generics/form_edit.html" %}
9 |
10 |
11 |
12 |
13 | {% load static %}
14 |
15 |
16 |
17 | {% endblock %}
18 |
--------------------------------------------------------------------------------
/tests/test_service_catalog/test_views/test_admin/test_tools/test_instance_hook/test_list.py:
--------------------------------------------------------------------------------
1 | from django.urls import reverse
2 |
3 | from tests.test_service_catalog.base import BaseTest
4 |
5 |
6 | class InstanceHooksListViewsTest(BaseTest):
7 |
8 | def setUp(self):
9 | super(InstanceHooksListViewsTest, self).setUp()
10 | self.url = reverse('service_catalog:instancehook_list')
11 |
12 | def test_get_list(self):
13 | response = self.client.get(self.url)
14 | self.assertEqual(200, response.status_code)
15 |
16 | def test_user_cannot_list(self):
17 | self.client.logout()
18 | self.client.login(username=self.standard_user, password=self.common_password)
19 | response = self.client.get(self.url)
20 | self.assertEqual(403, response.status_code)
21 |
--------------------------------------------------------------------------------
/tests/test_service_catalog/test_views/test_admin/test_tools/test_request_hook/test_list.py:
--------------------------------------------------------------------------------
1 | from django.urls import reverse
2 |
3 | from tests.test_service_catalog.base import BaseTest
4 |
5 |
6 | class RequestHooksListViewsTest(BaseTest):
7 |
8 | def setUp(self):
9 | super(RequestHooksListViewsTest, self).setUp()
10 | self.url = reverse('service_catalog:requesthook_list')
11 |
12 | def test_get_list(self):
13 | response = self.client.get(self.url)
14 | self.assertEqual(200, response.status_code)
15 |
16 | def test_user_cannot_list(self):
17 | self.client.logout()
18 | self.client.login(username=self.standard_user, password=self.common_password)
19 | response = self.client.get(self.url)
20 | self.assertEqual(403, response.status_code)
21 |
--------------------------------------------------------------------------------
/Squest/models/singleton_model.py:
--------------------------------------------------------------------------------
1 | from django.db.models import Model
2 | from django.core.cache import cache
3 |
4 |
5 | class SingletonModel(Model):
6 |
7 | class Meta:
8 | abstract = True
9 |
10 | def save(self, *args, **kwargs):
11 | self.pk = 1
12 | super(SingletonModel, self).save(*args, **kwargs)
13 | self.set_cache()
14 |
15 | def delete(self, *args, **kwargs):
16 | pass
17 |
18 | def set_cache(self):
19 | cache.set(self.__class__.__name__, self)
20 |
21 | @classmethod
22 | def load(cls):
23 | if cache.get(cls.__name__) is None:
24 | obj, created = cls.objects.get_or_create(pk=1)
25 | if not created:
26 | obj.set_cache()
27 | return obj
28 | return cache.get(cls.__name__)
29 |
--------------------------------------------------------------------------------
/k8s/squest_k8s/tasks/03-redis.yml:
--------------------------------------------------------------------------------
1 | - when: redis.enabled
2 | name: Install Redis Helm chart
3 | kubernetes.core.helm:
4 | name: redis
5 | release_namespace: "{{ squest_namespace }}"
6 | chart_version: "{{ redis_chart_version }}"
7 | chart_ref: oci://registry-1.docker.io/bitnamicharts/redis
8 | values: "{{ redis.helm_values }}"
9 |
10 | - when: not redis.enabled and squest_redis.existing_secret is not defined
11 | name: Create a secret for redis
12 | kubernetes.core.k8s:
13 | namespace: "{{ squest_namespace }}"
14 | definition:
15 | kind: Secret
16 | apiVersion: v1
17 | metadata:
18 | name: "redis"
19 | labels:
20 | app: squest
21 | service: redis
22 | data:
23 | redis-password: "{{ squest_redis.password | b64encode }}"
24 |
--------------------------------------------------------------------------------
/project-static/squest/css/squest-dark.css:
--------------------------------------------------------------------------------
1 | footer{
2 | z-index: auto !important;
3 | }
4 | /*fix select button color*/
5 | .btn-light {
6 | background-color: #343a40 !important;
7 | color: #fff !important;
8 | }
9 |
10 | .bg-dark table tr,.bg-dark blockquote,details.bg-dark pre {
11 | background-color: #343a40 !important;
12 | color: #fff !important;
13 | }
14 |
15 | .dtfc-fixed-left {
16 | background-color: #343a40 !important;
17 | z-index: 1;
18 | }
19 |
20 | input.form-control[disabled] {
21 | opacity: 0.4;
22 | }
23 |
24 | div.martor-preview.bg-dark > h1,
25 | div.martor-preview.bg-dark > h2,
26 | div.martor-preview.bg-dark > h3,
27 | div.martor-preview.bg-dark > h4,
28 | div.martor-preview.bg-dark > h5,
29 | div.martor-preview.bg-dark > h6 {
30 | color: white !important;
31 | }
32 |
--------------------------------------------------------------------------------
/service_catalog/api/views/__init__.py:
--------------------------------------------------------------------------------
1 | from service_catalog.api.views.instance_api_views import *
2 | from service_catalog.api.views.job_template_api_views import *
3 | from service_catalog.api.views.job_template_sync import *
4 | from service_catalog.api.views.operation_api_views import *
5 | from service_catalog.api.views.request_api_views import *
6 | from service_catalog.api.views.request_state_machine_api_view import *
7 | from service_catalog.api.views.service_api_views import *
8 | from service_catalog.api.views.tower_server_api_views import *
9 | from service_catalog.api.views.operation_survey_api_views import *
10 | from service_catalog.api.views.portfolio_api_views import *
11 | from service_catalog.api.views.approval_workflow_api_views import *
12 | from service_catalog.api.views.approval_step_api_views import *
13 |
--------------------------------------------------------------------------------
/service_catalog/migrations/0032_alter_operation_name_alter_operation_type.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 4.2.6 on 2023-11-20 11:01
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [
9 | ('service_catalog', '0031_service_attribute_definitions'),
10 | ]
11 |
12 | operations = [
13 | migrations.AlterField(
14 | model_name='operation',
15 | name='name',
16 | field=models.CharField(max_length=100),
17 | ),
18 | migrations.AlterField(
19 | model_name='operation',
20 | name='type',
21 | field=models.CharField(choices=[('CREATE', 'Create'), ('UPDATE', 'Update'), ('DELETE', 'Delete')], default='CREATE', max_length=10),
22 | ),
23 | ]
24 |
--------------------------------------------------------------------------------
/tests/test_swagger_view.py:
--------------------------------------------------------------------------------
1 | from django.contrib.auth.models import User
2 | from django.test import TestCase
3 | from django.urls import reverse
4 |
5 |
6 | class TestMonitoring(TestCase):
7 |
8 | def test_can_get_swagger_view(self):
9 | url = reverse('schema-swagger-ui') + "?format=openapi"
10 | testing_user = User.objects.create_user('stan1234', 'standard_user@hpe.com', 'password')
11 | self.client.force_login(testing_user)
12 | response = self.client.get(url)
13 | self.assertEqual(200, response.status_code)
14 |
15 | def test_cannot_get_swagger_view_when_logout(self):
16 | url = reverse('schema-swagger-ui') + "?format=openapi"
17 | self.client.logout()
18 | response = self.client.get(url)
19 | self.assertEqual(403, response.status_code)
20 |
--------------------------------------------------------------------------------
/project-static/squest/js/resource_group_attributes.js:
--------------------------------------------------------------------------------
1 | function load_resource_group_attributes(target_resource_group_id){
2 | var url = $("#ResourceGroupLinkForm").attr("data-attribute-url");
3 | var current_resource_group_id = $("#ResourceGroupLinkForm").attr("current-resource-group-id");
4 | $.ajax({
5 | url: url,
6 | data: {
7 | 'csrfmiddlewaretoken': csrf_token,
8 | 'current_resource_group_id': current_resource_group_id,
9 | 'target_resource_group_id': target_resource_group_id
10 | },
11 | success: function (data) {
12 | $("#id_consume_from_attribute_definition").html(data);
13 | },
14 | error: function(){
15 | console.log("Error during ajax call 'load_resource_group_attributes'");
16 | }
17 | });
18 | }
19 |
--------------------------------------------------------------------------------
/service_catalog/filters/operation_filter.py:
--------------------------------------------------------------------------------
1 | from django.forms import SelectMultiple
2 | from django_filters import MultipleChoiceFilter
3 |
4 | from Squest.utils.squest_filter import SquestFilter
5 | from service_catalog.models import Operation
6 | from service_catalog.models.operations import OperationType
7 |
8 |
9 | class OperationFilter(SquestFilter):
10 | class Meta:
11 | model = Operation
12 | fields = ['service', 'name', 'type', 'job_template__name', 'auto_accept', 'auto_process', 'process_timeout_second']
13 |
14 | type = MultipleChoiceFilter(
15 | choices=OperationType.choices,
16 | widget=SelectMultiple(attrs={'data-live-search': "true"}))
17 |
18 |
19 | class OperationFilterLimited(SquestFilter):
20 | class Meta:
21 | model = Operation
22 | fields = ['name']
23 |
--------------------------------------------------------------------------------
/service_catalog/migrations/0036_approvalworkflow_enabled.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 4.2.6 on 2023-11-21 19:48
2 |
3 | from django.db import migrations, models
4 | def set_enabled_to_all_workflow(apps, schema_editor):
5 | ApprovalWorkflow = apps.get_model("service_catalog", "ApprovalWorkflow")
6 | ApprovalWorkflow.objects.all().update(enabled=True)
7 |
8 | class Migration(migrations.Migration):
9 |
10 | dependencies = [
11 | ('service_catalog', '0035_alter_request_options'),
12 | ]
13 |
14 | operations = [
15 | migrations.AddField(
16 | model_name='approvalworkflow',
17 | name='enabled',
18 | field=models.BooleanField(default=False, help_text='Set to True to use the workflow'),
19 | ),
20 | migrations.RunPython(set_enabled_to_all_workflow)
21 | ]
22 |
--------------------------------------------------------------------------------
/templates/service_catalog/custom_columns/job_template_actions.html:
--------------------------------------------------------------------------------
1 |
7 |
8 |
9 |
11 |
12 |
13 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/tests/test_service_catalog/test_models/test_service.py:
--------------------------------------------------------------------------------
1 | from service_catalog.forms.form_utils import FormUtils
2 | from tests.test_service_catalog.base_test_request import BaseTestRequest
3 |
4 |
5 | class TestService(BaseTestRequest):
6 |
7 | def setUp(self):
8 | super(TestService, self).setUp()
9 |
10 | def test_bulk_set_permission_on_operation(self):
11 | for current_perm in self.service_test.operations.values_list("permission", flat=True):
12 | self.assertEqual(current_perm, FormUtils.get_default_permission_for_operation())
13 |
14 | # apply new perm
15 | self.service_test.bulk_set_permission_on_operation(self.admin_operation)
16 | for current_perm in self.service_test.operations.values_list("permission", flat=True):
17 | self.assertEqual(current_perm, self.admin_operation.id)
--------------------------------------------------------------------------------
/service_catalog/filters/custom_link_filter.py:
--------------------------------------------------------------------------------
1 | from django.forms import SelectMultiple
2 | from django_filters import MultipleChoiceFilter
3 |
4 | from Squest.utils.squest_filter import SquestFilter
5 | from service_catalog.models import CustomLink
6 |
7 |
8 | class CustomLinkFilter(SquestFilter):
9 | class Meta:
10 | model = CustomLink
11 | fields = ['name', 'services']
12 |
13 | def __init__(self, *args, **kwargs):
14 | super(CustomLinkFilter, self).__init__(*args, **kwargs)
15 | from service_catalog.models import Service
16 | self.filters['services'].field.choices = [(service.id, service.name) for service in Service.objects.all()]
17 |
18 | services = MultipleChoiceFilter(
19 | label="Service",
20 | choices=[],
21 | widget=SelectMultiple(attrs={'data-live-search': "true"}))
22 |
--------------------------------------------------------------------------------
/resource_tracker_v2/api/views/attribute_definition_api_views.py:
--------------------------------------------------------------------------------
1 | from Squest.utils.squest_api_views import SquestListCreateAPIView, SquestRetrieveUpdateDestroyAPIView
2 | from resource_tracker_v2.api.serializers.attribute_definition_serializers import AttributeDefinitionSerializer
3 | from resource_tracker_v2.filters.attribute_definition_filter import AttributeDefinitionFilter
4 | from resource_tracker_v2.models import AttributeDefinition
5 |
6 |
7 | class AttributeDefinitionList(SquestListCreateAPIView):
8 | queryset = AttributeDefinition.objects.all()
9 | serializer_class = AttributeDefinitionSerializer
10 | filterset_class = AttributeDefinitionFilter
11 |
12 |
13 | class AttributeDefinitionDetails(SquestRetrieveUpdateDestroyAPIView):
14 | queryset = AttributeDefinition.objects.all()
15 | serializer_class = AttributeDefinitionSerializer
16 |
--------------------------------------------------------------------------------
/service_catalog/tables/annoucement_tables.py:
--------------------------------------------------------------------------------
1 | from django.utils.html import format_html
2 | from django_tables2 import TemplateColumn, Column
3 |
4 | from Squest.utils.squest_table import SquestTable
5 | from service_catalog.models import Announcement
6 |
7 |
8 | class AnnouncementTable(SquestTable):
9 | actions = TemplateColumn(template_name='generics/custom_columns/generic_actions.html', orderable=False)
10 | created_by__username = Column(verbose_name='Owner')
11 |
12 | class Meta:
13 | model = Announcement
14 | attrs = {"id": "announcement_table", "class": "table squest-pagination-tables"}
15 | fields = ("title", "date_start", "date_stop", "created_by__username", "type", "actions")
16 |
17 | def render_type(self, value, record):
18 | return format_html(f'{ value }')
19 |
--------------------------------------------------------------------------------
/Squest/api/celery_tasks_views.py:
--------------------------------------------------------------------------------
1 | from django_celery_results.models import TaskResult
2 | from drf_yasg.utils import swagger_auto_schema
3 | from rest_framework import status
4 | from rest_framework.generics import get_object_or_404
5 | from rest_framework.permissions import IsAdminUser
6 | from rest_framework.response import Response
7 | from rest_framework.views import APIView
8 |
9 | from service_catalog.api.serializers import TaskResultSerializer
10 |
11 |
12 | class CeleryTaskView(APIView):
13 |
14 | permission_classes = [IsAdminUser]
15 |
16 | @swagger_auto_schema(responses={200: TaskResultSerializer()})
17 | def get(self, request, task_id):
18 | task_result = get_object_or_404(TaskResult, id=task_id)
19 | serialized_task = TaskResultSerializer(task_result)
20 | return Response(serialized_task.data, status=status.HTTP_200_OK)
21 |
--------------------------------------------------------------------------------
/templates/profiles/custom_columns/user_roles.html:
--------------------------------------------------------------------------------
1 | {% with class_name=object|to_class_name|lower %}
2 | {% for group in record.groups.all %}
3 | {% has_perm request.user "profiles.view_role" group.role as can_view_role %}
4 |
15 | {% endfor %}
16 | {% endwith %}
17 |
--------------------------------------------------------------------------------
/service_catalog/migrations/0041_operation_validators.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 4.2.6 on 2023-12-20 13:20
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [
9 | ('service_catalog', '0040_alter_towersurveyfield_unique_together'),
10 | ]
11 |
12 | operations = [
13 | migrations.AddField(
14 | model_name='operation',
15 | name='validators',
16 | field=models.CharField(blank=True, max_length=200, null=True, verbose_name='Survey validators'),
17 | ),
18 | migrations.CreateModel(
19 | name="FakeInstance",
20 | fields=[],
21 | options={
22 | "managed": False,
23 | "proxy": True,
24 | },
25 | bases=("service_catalog.instance",),
26 | ),
27 | ]
28 |
--------------------------------------------------------------------------------
/tests/test_profiles/test_forms/test_notification_filter_form.py:
--------------------------------------------------------------------------------
1 | from profiles.forms import InstanceNotificationForm, RequestNotificationForm
2 | from tests.test_profiles.base.base_test_profile import BaseTestProfile
3 |
4 |
5 | class TestNotificationForm(BaseTestProfile):
6 |
7 | def test_m2m_saved(self):
8 | data = {
9 | "name": "test_notification_form",
10 | "services": [self.service_test]
11 | }
12 | form = InstanceNotificationForm(user=self.standard_user, data=data)
13 | form.is_valid()
14 | saved_filter = form.save()
15 | self.assertIn(self.service_test, saved_filter.services.all())
16 |
17 | form = RequestNotificationForm(user=self.standard_user, data=data)
18 | form.is_valid()
19 | saved_filter = form.save()
20 | self.assertIn(self.service_test, saved_filter.services.all())
21 |
--------------------------------------------------------------------------------
/playbook_examples/file_service_example/delete.yml:
--------------------------------------------------------------------------------
1 | # ansible-playbook playbook_examples/file_service_example/create.yml \
2 | # -i playbook_examples/squest_inventory/inventory \
3 | # --extra-vars @playbook_examples/squest_inventory/squest_extra_vars/delete.yml
4 |
5 | ---
6 | - hosts: squest_testing
7 | become: False
8 | gather_facts: False
9 |
10 | tasks:
11 | - name: Get UUID
12 | set_fact:
13 | uuid_file: "{{ squest['request']['instance']['spec']['uuid_file'] }}"
14 |
15 | - name: Generate path
16 | set_fact:
17 | file_path: "/tmp/squest_functional_test/{{ uuid_file }}"
18 |
19 | - name: Prints variables
20 | ansible.builtin.debug:
21 | msg:
22 | - "UUID: {{ uuid_file }}"
23 |
24 | - name: Recursively remove directory
25 | ansible.builtin.file:
26 | path: "{{ file_path }}"
27 | state: absent
28 |
--------------------------------------------------------------------------------
/service_catalog/tables/service_tables.py:
--------------------------------------------------------------------------------
1 | from django_tables2 import TemplateColumn, LinkColumn
2 |
3 | from Squest.utils.squest_table import SquestTable
4 | from service_catalog.models import Service
5 |
6 |
7 | class ServiceTable(SquestTable):
8 | actions = TemplateColumn(template_name='service_catalog/custom_columns/service_actions.html', orderable=False)
9 | enabled = TemplateColumn(template_name='generics/custom_columns/generic_boolean_check.html')
10 | operations = TemplateColumn(template_name='service_catalog/custom_columns/service_operations.html',
11 | verbose_name="Operations", orderable=False)
12 | name = LinkColumn()
13 |
14 | class Meta:
15 | model = Service
16 | attrs = {"id": "service_table", "class": "table squest-pagination-tables"}
17 | fields = ("name", "description", "enabled", "operations", "actions")
18 |
--------------------------------------------------------------------------------
/tests/test_service_catalog/test_views/test_customer/test_instance/test_instance_details.py:
--------------------------------------------------------------------------------
1 | from django.urls import reverse
2 |
3 | from service_catalog.models import InstanceState
4 | from tests.test_service_catalog.base_test_request import BaseTestRequest
5 |
6 |
7 | class TestCustomerInstanceDetails(BaseTestRequest):
8 |
9 | def setUp(self):
10 | super(TestCustomerInstanceDetails, self).setUp()
11 | self.test_instance.state = InstanceState.AVAILABLE
12 | self.test_instance.save()
13 | self.args = {
14 | "pk": self.test_instance.id
15 | }
16 |
17 | def test_get_instance_details(self):
18 | url = reverse('service_catalog:instance_details', kwargs=self.args)
19 | response = self.client.get(url)
20 | self.assertEqual(200, response.status_code)
21 | self.assertIsNotNone(response.context['operations_table'])
22 |
--------------------------------------------------------------------------------
/service_catalog/migrations/0038_alter_towersurveyfield_unique_together_and_more.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 4.2.6 on 2023-12-08 14:20
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [
9 | ('service_catalog', '0037_alter_request_options_remove_approvalstep_next_and_more'),
10 | ]
11 |
12 | operations = [
13 | migrations.AlterUniqueTogether(
14 | name='towersurveyfield',
15 | unique_together=set(),
16 | ),
17 | migrations.AddField(
18 | model_name='towersurveyfield',
19 | name='position',
20 | field=models.IntegerField(default=0),
21 | ),
22 | migrations.AlterUniqueTogether(
23 | name='towersurveyfield',
24 | unique_together={('operation', 'position', 'variable')},
25 | ),
26 | ]
27 |
--------------------------------------------------------------------------------
/service_catalog/tables/tower_server_tables.py:
--------------------------------------------------------------------------------
1 | from django_tables2 import TemplateColumn, LinkColumn
2 |
3 | from Squest.utils.squest_table import SquestTable
4 | from service_catalog.models import TowerServer
5 |
6 |
7 | class TowerServerTable(SquestTable):
8 | name = LinkColumn()
9 | host = TemplateColumn(template_name='service_catalog/custom_columns/tower_server_host.html')
10 | jobtemplate = TemplateColumn(template_name='service_catalog/custom_columns/tower_server_job_templates.html',
11 | verbose_name="Job templates")
12 | actions = TemplateColumn(template_name='service_catalog/custom_columns/tower_server_actions.html', orderable=False)
13 |
14 | class Meta:
15 | model = TowerServer
16 | attrs = {"id": "tower_server_table", "class": "table squest-pagination-tables"}
17 | fields = ("name", "host", "jobtemplate", "actions")
18 |
--------------------------------------------------------------------------------
/service_catalog/views/custom_link.py:
--------------------------------------------------------------------------------
1 | from Squest.utils.squest_views import *
2 | from service_catalog.filters.custom_link_filter import CustomLinkFilter
3 | from service_catalog.forms.custom_link_form import CustomLinkForm
4 | from service_catalog.models import CustomLink
5 | from service_catalog.tables.custom_link_table import CustomLinkTable
6 |
7 |
8 | class CustomLinkListView(SquestListView):
9 | table_class = CustomLinkTable
10 | model = CustomLink
11 | filterset_class = CustomLinkFilter
12 |
13 |
14 | class CustomLinkCreateView(SquestCreateView):
15 | model = CustomLink
16 | form_class = CustomLinkForm
17 |
18 |
19 | class CustomLinkEditView(SquestUpdateView):
20 | model = CustomLink
21 | form_class = CustomLinkForm
22 |
23 |
24 | class CustomLinkDeleteView(SquestDeleteView):
25 | model = CustomLink
26 | template_name = 'generics/confirm-delete-template.html'
27 |
--------------------------------------------------------------------------------
/service_catalog/api/serializers/tower_server_serializer.py:
--------------------------------------------------------------------------------
1 | from rest_framework.serializers import ModelSerializer, ValidationError
2 |
3 | from service_catalog.models import TowerServer
4 |
5 |
6 | class TowerServerSerializer(ModelSerializer):
7 | class Meta:
8 | model = TowerServer
9 | exclude = ('token',)
10 |
11 |
12 | class TowerServerCreateSerializer(ModelSerializer):
13 | class Meta:
14 | model = TowerServer
15 | fields = '__all__'
16 |
17 | def validate_extra_vars(self, value):
18 | if value is None or not isinstance(value, dict):
19 | raise ValidationError("Please enter a valid JSON. Empty value is {} for JSON.")
20 | return value
21 |
22 | def to_representation(self, tower_server):
23 | representation = super().to_representation(tower_server)
24 | representation.pop("token")
25 | return representation
26 |
--------------------------------------------------------------------------------
/service_catalog/migrations/0016_alter_request_options.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 3.2.13 on 2023-07-31 10:12
2 |
3 | from django.db import migrations
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [
9 | ('service_catalog', '0015_auto_20230728_1442'),
10 | ]
11 |
12 | operations = [
13 | migrations.AlterModelOptions(
14 | name='request',
15 | options={'default_permissions': ('add', 'change', 'delete', 'view', 'list'), 'ordering': ['-date_submitted'], 'permissions': [('accept_request', 'Can accept request'), ('cancel_request', 'Can cancel request'), ('reject_request', 'Can reject request'), ('archive_request', 'Can archive request'), ('unarchive_request', 'Can unarchive request'), ('resubmit_request', 'Can re-submit request'), ('process_request', 'Can process request'), ('need_info_request', 'Can ask info request')]},
16 | ),
17 | ]
18 |
--------------------------------------------------------------------------------
/service_catalog/migrations/0027_alter_approvalworkflow_scopes.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 3.2.13 on 2023-09-22 12:42
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 | dependencies = [
8 | ('profiles', '0019_alter_quota_options'),
9 | ('service_catalog', '0026_auto_20230919_1353'),
10 | ]
11 |
12 | operations = [
13 | migrations.AlterField(
14 | model_name='approvalworkflow',
15 | name='scopes',
16 | field=models.ManyToManyField(blank=True,
17 | help_text='This workflow will be triggered for the following scopes. Leave empty to trigger for all scopes',
18 | related_name='approval_workflows', to='profiles.Scope',
19 | verbose_name='Restricted scopes'),
20 | ),
21 | ]
22 |
--------------------------------------------------------------------------------
/tests/test_profiles/test_urls/test_user.py:
--------------------------------------------------------------------------------
1 | from tests.test_profiles.base.base_test_profile import BaseTestProfile
2 | from tests.permission_endpoint import TestingGetContextView, TestPermissionEndpoint
3 |
4 |
5 | class TestProfilesUserPermissionsViews(BaseTestProfile, TestPermissionEndpoint):
6 | def test_user_views(self):
7 | testing_view_list = [
8 | # TODO: to be tested when User has been replaced by SquestUser (list_user permission not defined)
9 | # TestingGetUIViews(
10 | # url='profiles:user_list',
11 | # perm_str_list=['auth.list_user'],
12 | # ),
13 | TestingGetContextView(
14 | url='profiles:user_details',
15 | perm_str_list=['auth.view_user'],
16 | url_kwargs={'pk': self.standard_user.id}
17 | )
18 | ]
19 | self.run_permissions_tests(testing_view_list)
--------------------------------------------------------------------------------
/k8s/deploy.yml:
--------------------------------------------------------------------------------
1 | - name: "Deploy Squest"
2 | hosts: localhost
3 | gather_facts: false
4 | module_defaults:
5 | kubernetes.core.k8s:
6 | kubeconfig: "{{ k8s_kubeconfig_path }}"
7 | kubernetes.core.k8s_info:
8 | kubeconfig: "{{ k8s_kubeconfig_path }}"
9 | kubernetes.core.helm:
10 | kubeconfig: "{{ k8s_kubeconfig_path }}"
11 |
12 | pre_tasks:
13 |
14 | - when: k8s_kubeconfig_path is undefined
15 | name: 'Fail if k8s_kubeconfig_path is not defined'
16 | ansible.builtin.fail:
17 | msg: 'Please make sure you set k8s_kubeconfig_path'
18 |
19 | - when:
20 | - ssh_private_key_path is undefined
21 | - squest_django.externalize_backup_via_rsync.enabled | bool
22 | name: 'Fail if ssh_private_key_path is not defined'
23 | ansible.builtin.fail:
24 | msg: 'Please make sure you set ssh_private_key_path'
25 |
26 | roles:
27 | - role: squest_k8s
28 |
--------------------------------------------------------------------------------
/k8s/squest_k8s/tasks/02-rabbitmq.yml:
--------------------------------------------------------------------------------
1 | - when: rabbitmq.enabled
2 | name: Install RabbitMQ Helm chart
3 | kubernetes.core.helm:
4 | name: rabbitmq
5 | release_namespace: "{{ squest_namespace }}"
6 | chart_version: "{{ rabbitmq_chart_version }}"
7 | chart_ref: oci://registry-1.docker.io/bitnamicharts/rabbitmq
8 | values: "{{ rabbitmq.helm_values }}"
9 |
10 | - when: not rabbitmq.enabled and squest_rabbitmq.existing_secret is not defined
11 | name: Create a secret for rabbitmq
12 | kubernetes.core.k8s:
13 | namespace: "{{ squest_namespace }}"
14 | definition:
15 | kind: Secret
16 | apiVersion: v1
17 | metadata:
18 | name: "rabbitmq"
19 | labels:
20 | app: squest
21 | service: rabbitmq
22 | data:
23 | rabbitmq-erlang-cookie: "{{ squest_rabbitmq.erlang_cookie | b64encode }}"
24 | rabbitmq-password: "{{ squest_rabbitmq.password | b64encode }}"
25 |
--------------------------------------------------------------------------------
/resource_tracker_v2/tables/transformer_table.py:
--------------------------------------------------------------------------------
1 | from django_tables2 import TemplateColumn, LinkColumn, Column
2 |
3 | from Squest.utils.squest_table import SquestTable
4 | from resource_tracker_v2.models import Transformer
5 |
6 |
7 | class TransformerTable(SquestTable):
8 | class Meta:
9 | model = Transformer
10 | attrs = {"id": "attribute_definition_table", "class": "table squest-pagination-tables"}
11 | fields = ("attribute_definition__name", "consume_from_resource_group", "consume_from_attribute_definition",
12 | "factor", "actions")
13 |
14 | attribute_definition__name = Column()
15 | consume_from_resource_group = LinkColumn()
16 | consume_from_attribute_definition = Column(verbose_name="On attribute")
17 | actions = TemplateColumn(
18 | template_name='resource_tracker_v2/resource_group/custom_columns/resource_group_attribute_actions.html',
19 | orderable=False)
20 |
--------------------------------------------------------------------------------
/profiles/forms/token_forms.py:
--------------------------------------------------------------------------------
1 | from django.utils import timezone
2 | from tempus_dominus.widgets import DateTimePicker
3 |
4 | from Squest.utils.squest_model_form import SquestModelForm
5 | from profiles.models import Token
6 |
7 |
8 | class TokenForm(SquestModelForm):
9 | class Meta:
10 | model = Token
11 | fields = ['description', 'expires']
12 |
13 | def __init__(self, *args, **kwargs):
14 | super(TokenForm, self).__init__(*args, **kwargs)
15 | self.fields['expires'].widget = DateTimePicker(
16 | options={
17 | 'useCurrent': True,
18 | 'timeZone': str(timezone.get_current_timezone()),
19 | 'collapse': False,
20 | 'minDate': str(timezone.now().astimezone().strftime("%Y-%m-%d %H:%M:%S")),
21 | }, attrs={
22 | 'append': 'fa fa-calendar',
23 | 'icon_toggle': True,
24 | }
25 | )
26 |
--------------------------------------------------------------------------------
/resource_tracker_v2/models/resource_attribute.py:
--------------------------------------------------------------------------------
1 | from django.db.models import PositiveIntegerField, ForeignKey, CASCADE
2 |
3 | from Squest.utils.squest_model import SquestModel
4 |
5 |
6 | class ResourceAttribute(SquestModel):
7 | value = PositiveIntegerField(default=0)
8 |
9 | resource = ForeignKey('Resource',
10 | on_delete=CASCADE,
11 | related_name='resource_attributes',
12 | related_query_name='resource_attribute',
13 | null=True)
14 |
15 | attribute_definition = ForeignKey('AttributeDefinition',
16 | on_delete=CASCADE,
17 | related_name='resource_attributes',
18 | related_query_name='resource_attribute',
19 | null=True)
20 |
21 | def __str__(self):
22 | return str(self.value)
23 |
--------------------------------------------------------------------------------
/service_catalog/migrations/0028_set_last_update_on_request.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 3.2.13 on 2023-09-27 08:53
2 |
3 | from django.db import migrations
4 |
5 |
6 | def update_requests(apps, schema_editor):
7 | Request = apps.get_model('service_catalog', 'Request')
8 | for request in Request.objects.all():
9 | Request.objects.filter(pk=request.pk).update(created=request.date_submitted,
10 | last_updated=request.date_submitted)
11 | from service_catalog.models import RequestState
12 | if request.state == RequestState.COMPLETE:
13 | Request.objects.filter(pk=request.pk).update(last_updated=request.date_complete)
14 |
15 |
16 | class Migration(migrations.Migration):
17 |
18 | dependencies = [
19 | ('service_catalog', '0027_alter_approvalworkflow_scopes'),
20 | ]
21 |
22 | operations = [
23 | migrations.RunPython(update_requests),
24 | ]
25 |
--------------------------------------------------------------------------------
/Squest/api/authentication.py:
--------------------------------------------------------------------------------
1 | from rest_framework import authentication, exceptions
2 |
3 | from profiles.models import Token
4 |
5 |
6 | class TokenAuthentication(authentication.TokenAuthentication):
7 | """
8 | A custom authentication scheme which enforces Token expiration times.
9 | """
10 | model = Token
11 | keyword = 'Bearer'
12 |
13 | def authenticate_credentials(self, key):
14 | model = self.get_model()
15 | try:
16 | token = model.objects.prefetch_related('user').get(key=key)
17 | except model.DoesNotExist:
18 | raise exceptions.AuthenticationFailed("Invalid token")
19 | # Enforce the Token's expiration time, if one has been set.
20 | if token.is_expired():
21 | raise exceptions.AuthenticationFailed("Token expired")
22 | if not token.user.is_active:
23 | raise exceptions.AuthenticationFailed("User inactive")
24 | return token.user, token
25 |
--------------------------------------------------------------------------------
/service_catalog/api/serializers/approval_step_state_serializer.py:
--------------------------------------------------------------------------------
1 | from rest_framework.serializers import ModelSerializer
2 |
3 | from service_catalog.models import ApprovalStepState
4 |
5 |
6 | class ApprovalStepStateSerializer(ModelSerializer):
7 |
8 | class Meta:
9 | model = ApprovalStepState
10 | fields = ['id', 'approval_step', 'state', 'updated_by', 'date_updated', 'fill_in_survey']
11 |
12 | def __init__(self, *args, **kwargs):
13 | self.user = kwargs.pop('user')
14 | super(ApprovalStepStateSerializer, self).__init__(*args, **kwargs)
15 |
16 | def to_representation(self, current_step):
17 | representation = super().to_representation(current_step)
18 | if not self.user.has_perm(current_step.approval_step.permission.permission_str,
19 | current_step.approval_workflow_state.request):
20 | representation.pop("fill_in_survey")
21 | return representation
22 |
--------------------------------------------------------------------------------
/tests/test_service_catalog/test_views/test_admin/test_tools/test_catalog/test_operations/test_list.py:
--------------------------------------------------------------------------------
1 | from django.urls import reverse
2 |
3 | from tests.test_service_catalog.base import BaseTest
4 |
5 |
6 | class OperationListTestCase(BaseTest):
7 |
8 | def setUp(self):
9 | super(OperationListTestCase, self).setUp()
10 |
11 | self.url = reverse('service_catalog:operation_list')
12 |
13 | def test_get_operation_list(self):
14 | response = self.client.get(self.url)
15 | self.assertEqual(200, response.status_code)
16 |
17 | def test_customer_can_get_operation_list(self):
18 | self.client.force_login(self.standard_user)
19 | response = self.client.get(self.url)
20 | self.assertEqual(200, response.status_code)
21 |
22 | def test_cannot_get_operation_list_logout(self):
23 | self.client.logout()
24 | response = self.client.get(self.url)
25 | self.assertEqual(302, response.status_code)
26 |
--------------------------------------------------------------------------------
/service_catalog/forms/request_message_forms.py:
--------------------------------------------------------------------------------
1 | from Squest.utils.squest_model_form import SquestModelForm
2 | from service_catalog.models import RequestMessage
3 |
4 |
5 | class RequestMessageForm(SquestModelForm):
6 | class Meta:
7 | model = RequestMessage
8 | fields = ["content"]
9 |
10 | def __init__(self, *args, **kwargs):
11 | self.sender = kwargs.pop('sender')
12 | self.request = kwargs.pop('target_request')
13 | super(RequestMessageForm, self).__init__(*args, **kwargs)
14 |
15 | def save(self, commit=True, send_notification=True):
16 | message = super(RequestMessageForm, self).save(commit=False)
17 | message.request = self.request
18 | message.sender = self.sender
19 | message.save()
20 | if send_notification:
21 | from service_catalog.mail_utils import send_mail_new_comment_on_request
22 | send_mail_new_comment_on_request(message)
23 | return message
24 |
--------------------------------------------------------------------------------
/tests/test_service_catalog/test_views/test_admin/test_tools/test_custom_links/test_list.py:
--------------------------------------------------------------------------------
1 | from django.urls import reverse
2 |
3 | from tests.test_service_catalog.test_views.test_admin.test_tools.test_custom_links.base_test_custom_link import \
4 | BaseTestCustomLink
5 |
6 |
7 | class CustomLinksListViewsTest(BaseTestCustomLink):
8 |
9 | def setUp(self):
10 | super(CustomLinksListViewsTest, self).setUp()
11 | self.url = reverse('service_catalog:customlink_list')
12 |
13 | def test_get_list(self):
14 | response = self.client.get(self.url)
15 | self.assertEqual(200, response.status_code)
16 | self.assertEqual(len(response.context["table"].data.data), 1)
17 |
18 | def test_user_cannot_list(self):
19 | self.client.logout()
20 | self.client.login(username=self.standard_user, password=self.common_password)
21 | response = self.client.get(self.url)
22 | self.assertEqual(403, response.status_code)
23 |
--------------------------------------------------------------------------------
/tests/test_service_catalog/test_views/test_admin/test_tools/test_custom_links/base_test_custom_link.py:
--------------------------------------------------------------------------------
1 | from django.test import TestCase
2 | from rest_framework.test import APITestCase
3 |
4 | from service_catalog.models import CustomLink
5 | from tests.test_service_catalog.base_test_request import BaseTestRequestCommon
6 |
7 | class BaseTestCustomLinkCommon(BaseTestRequestCommon):
8 |
9 | def setUp(self):
10 | super(BaseTestCustomLinkCommon, self).setUp()
11 |
12 | self.test_custom_link = CustomLink.objects.create(name="test_custom_link",
13 | text="custom_link",
14 | url="https://custom-link.domain")
15 | self.test_custom_link.services.set([self.service_test])
16 |
17 | class BaseTestCustomLink(TestCase, BaseTestCustomLinkCommon):
18 | pass
19 |
20 |
21 | class BaseTestCustomLinkAPI(APITestCase, BaseTestCustomLinkCommon):
22 | pass
23 |
--------------------------------------------------------------------------------
/templates/generics/breadcrumbs.html:
--------------------------------------------------------------------------------
1 | {% if breadcrumbs %}
2 |
3 | {% for breadcrumb in breadcrumbs %}
4 | {% if breadcrumb == breadcrumbs|last or breadcrumb.url == ""%}
5 | - {{ breadcrumb.text }}
6 | {% elif breadcrumb == breadcrumbs|last %}
7 | -
8 | {{ breadcrumb.text }}
9 |
10 | {% elif breadcrumb.url == "" %}
11 | - {{ breadcrumb.text }}
12 | {% else %}
13 | -
14 | {{ breadcrumb.text }}
15 |
16 | {% endif %}
17 | {% endfor %}
18 |
19 | {% elif title %}
20 | {{ title }}
21 | {% endif %}
22 |
--------------------------------------------------------------------------------
/service_catalog/filters/support_filter.py:
--------------------------------------------------------------------------------
1 | from django.forms import SelectMultiple, HiddenInput
2 | from django_filters import MultipleChoiceFilter
3 |
4 | from Squest.utils.squest_filter import SquestFilter
5 | from service_catalog.models import Support
6 | from service_catalog.models.support import SupportState
7 |
8 |
9 | class SupportFilter(SquestFilter):
10 | class Meta:
11 | model = Support
12 | fields = ['title', 'instance__id', 'instance__name', 'instance__service', 'opened_by', 'state']
13 |
14 | state = MultipleChoiceFilter(
15 | choices=SupportState.choices,
16 | widget=SelectMultiple(attrs={'data-live-search': "true"}))
17 |
18 | def __init__(self, *args, **kwargs):
19 | super(SupportFilter, self).__init__(*args, **kwargs)
20 | self.filters['instance__name'].field.label = "Instance"
21 | self.filters['instance__service'].field.label = "Service"
22 | self.filters['instance__id'].field.widget = HiddenInput()
23 |
--------------------------------------------------------------------------------
/profiles/forms/model_permission_form.py:
--------------------------------------------------------------------------------
1 | from Squest.utils.squest_model_form import SquestModelForm
2 | from profiles.models.squest_permission import Permission
3 |
4 |
5 | class ModelPermissionForm(SquestModelForm):
6 | class Meta:
7 | model = Permission
8 | exclude = ['content_type']
9 |
10 | def __init__(self, content_type, *args, **kwargs):
11 | # get arguments from instance
12 | self.permission_content_type = content_type
13 | super().__init__(*args, **kwargs)
14 | self.fields['name'].help_text = f'A short description of the permission.'
15 | self.fields['codename'].help_text = f'Unique identifier for the permission in camel case format. ' \
16 | f'E.g: approve_custom_step'
17 |
18 | def save(self, commit=True):
19 | permission = super().save(False)
20 | permission.content_type = self.permission_content_type
21 | permission.save()
22 | return permission
23 |
--------------------------------------------------------------------------------
/profiles/tables/notification_filter_table.py:
--------------------------------------------------------------------------------
1 | from django_tables2 import TemplateColumn
2 |
3 | from Squest.utils.squest_table import SquestTable
4 | from profiles.models import InstanceNotification, RequestNotification
5 |
6 |
7 | class RequestNotificationFilterTable(SquestTable):
8 | actions = TemplateColumn(template_name='generics/custom_columns/generic_actions.html', orderable=False)
9 |
10 | class Meta:
11 | model = RequestNotification
12 | attrs = {"id": "request_notification_filter__table", "class": "table squest-pagination-tables "}
13 | fields = ("name", "actions")
14 |
15 |
16 | class InstanceNotificationFilterTable(SquestTable):
17 | actions = TemplateColumn(template_name='generics/custom_columns/generic_actions.html', orderable=False)
18 |
19 | class Meta:
20 | model = InstanceNotification
21 | attrs = {"id": "support_notification_filter__table", "class": "table squest-pagination-tables "}
22 | fields = ("name", "actions")
23 |
--------------------------------------------------------------------------------
/Squest/utils/ansible_when.py:
--------------------------------------------------------------------------------
1 | import logging
2 |
3 | from jinja2 import Template, UndefinedError, TemplateSyntaxError
4 |
5 | logger = logging.getLogger(__name__)
6 |
7 | class AnsibleWhen(object):
8 |
9 | @classmethod
10 | def when_render(cls, context, when_string):
11 | if when_string is None or when_string == "" or context is None:
12 | return False
13 | template_string = "{% if " + when_string + " %}True{% else %}{% endif %}"
14 | try:
15 | template = Template(template_string)
16 | except TemplateSyntaxError:
17 | logger.warning(f"when_render error when templating: {context} with string '{when_string}'")
18 | return False
19 | try:
20 | template_rendered = template.render(context)
21 | return bool(template_rendered)
22 | except UndefinedError:
23 | logger.warning(f"when_render error when templating: {context} with string '{when_string}'")
24 | return False
25 |
--------------------------------------------------------------------------------
/profiles/forms/scope_form.py:
--------------------------------------------------------------------------------
1 | from django.contrib.auth.models import User
2 | from django.forms import ModelMultipleChoiceField
3 |
4 | from Squest.utils.squest_form import SquestForm
5 | from profiles.models import Role
6 |
7 |
8 | class ScopeCreateRBACForm(SquestForm):
9 | roles = ModelMultipleChoiceField(
10 | queryset=Role.objects.all(),
11 | required=True,
12 | )
13 | users = ModelMultipleChoiceField(
14 | queryset=User.objects.none(),
15 | required=True,
16 | )
17 |
18 | def __init__(self, *args, **kwargs):
19 | self.scope = kwargs.pop('scope')
20 | super(ScopeCreateRBACForm, self).__init__(*args, **kwargs)
21 | self.fields["users"].queryset = self.scope.get_potential_users()
22 |
23 | def save(self):
24 | for role in self.cleaned_data.get('roles'):
25 | group = self.scope.get_rbac(role)
26 | for user in self.cleaned_data.get('users'):
27 | self.scope.add_user_in_role(user, role)
28 |
--------------------------------------------------------------------------------
/resource_tracker_v2/forms/attribute_definition_form.py:
--------------------------------------------------------------------------------
1 | from django.forms import ModelMultipleChoiceField
2 |
3 | from Squest.utils.squest_model_form import SquestModelForm
4 | from resource_tracker_v2.models import AttributeDefinition
5 | from service_catalog.models import Service
6 |
7 |
8 | class AttributeDefinitionForm(SquestModelForm):
9 | class Meta:
10 | model = AttributeDefinition
11 | fields = ["name", "description"]
12 |
13 | services = ModelMultipleChoiceField(queryset=Service.objects.all(), required=False)
14 |
15 | def __init__(self, *args, **kwargs):
16 | super(AttributeDefinitionForm, self).__init__(*args, **kwargs)
17 | if self.instance.id:
18 | self.fields['services'].initial = [service for service in self.instance.services.all()]
19 |
20 | def save(self, commit=True):
21 | attribute_definition = super().save(commit)
22 | attribute_definition.services.set(self.cleaned_data['services'])
23 | return attribute_definition
24 |
--------------------------------------------------------------------------------
/templates/service_catalog/buttons/request_state_machine.html:
--------------------------------------------------------------------------------
1 | {% has_perm request.user "service_catalog.archive_request" object as can_archive_request %}
2 | {% has_perm request.user "service_catalog.unarchive_request" object as can_unarchive_request %}
3 | {% with args_filter="archive,"|addstr:object.id %}
4 | {% if args_filter|can_proceed_request_action and can_archive_request %}
5 |
8 |
9 |
10 | {% endif %}
11 | {% endwith %}
12 | {% with args_filter="unarchive,"|addstr:object.id %}
13 | {% if args_filter|can_proceed_request_action and can_unarchive_request %}
14 |
17 |
18 |
19 | {% endif %}
20 | {% endwith %}
21 |
--------------------------------------------------------------------------------
/service_catalog/api/views/tower_server_api_views.py:
--------------------------------------------------------------------------------
1 | from Squest.utils.squest_api_views import SquestListCreateAPIView, SquestRetrieveUpdateDestroyAPIView
2 | from service_catalog.api.serializers import TowerServerSerializer, TowerServerCreateSerializer
3 | from service_catalog.filters.tower_server_filter import TowerServerFilter
4 | from service_catalog.models import TowerServer
5 |
6 |
7 | class TowerServerList(SquestListCreateAPIView):
8 | queryset = TowerServer.objects.all()
9 | filterset_class = TowerServerFilter
10 |
11 | def get_serializer_class(self):
12 | if self.request.method in ["POST"]:
13 | return TowerServerCreateSerializer
14 | return TowerServerSerializer
15 |
16 |
17 | class TowerServerDetails(SquestRetrieveUpdateDestroyAPIView):
18 | queryset = TowerServer.objects.all()
19 |
20 | def get_serializer_class(self):
21 | if self.request.method in ["PATCH", "PUT"]:
22 | return TowerServerCreateSerializer
23 | return TowerServerSerializer
24 |
--------------------------------------------------------------------------------
/service_catalog/migrations/0035_alter_request_options.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 4.2.6 on 2023-11-16 13:19
2 |
3 | from django.db import migrations
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [
9 | ('service_catalog', '0034_alter_request_approval_workflow_state'),
10 | ]
11 |
12 | operations = [
13 | migrations.AlterModelOptions(
14 | name='request',
15 | options={'default_permissions': ('add', 'change', 'delete', 'view', 'list'), 'ordering': ['-last_updated'], 'permissions': [('accept_request', 'Can accept request'), ('cancel_request', 'Can cancel request'), ('reject_request', 'Can reject request'), ('archive_request', 'Can archive request'), ('unarchive_request', 'Can unarchive request'), ('re_submit_request', 'Can re-submit request'), ('process_request', 'Can process request'), ('need_info_request', 'Can ask info request'), ('view_admin_survey', 'Can view admin survey'), ('list_approvers', 'Can view who can accept')]},
16 | ),
17 | ]
18 |
--------------------------------------------------------------------------------
/service_catalog/migrations/0022_auto_20230906_1539.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 3.2.13 on 2023-09-06 13:39
2 |
3 | from django.db import migrations
4 |
5 |
6 |
7 | def update_current_pending_instances(apps, schema_editor):
8 | from service_catalog.models import InstanceState, RequestState
9 | Instance = apps.get_model('service_catalog', 'Instance')
10 | for pending_instance in Instance.objects.filter(state=InstanceState.PENDING):
11 | if pending_instance.request_set.count() == 1:
12 | request = pending_instance.request_set.first()
13 | if request.state in [RequestState.REJECTED, RequestState.CANCELED]:
14 | pending_instance.state = InstanceState.ABORTED
15 | pending_instance.save()
16 |
17 |
18 | class Migration(migrations.Migration):
19 |
20 | dependencies = [
21 | ('service_catalog', '0021_approvalstep_auto_accept_condition'),
22 | ]
23 |
24 | operations = [
25 | migrations.RunPython(update_current_pending_instances),
26 | ]
27 |
--------------------------------------------------------------------------------
/tests/test_service_catalog/test_urls/test_doc.py:
--------------------------------------------------------------------------------
1 |
2 | from service_catalog.models import Doc
3 | from tests.test_service_catalog.base_test_request import BaseTestRequest
4 | from tests.permission_endpoint import TestingGetContextView, TestPermissionEndpoint
5 |
6 |
7 | class TestServiceCatalogDocPermissionsViews(BaseTestRequest, TestPermissionEndpoint):
8 | def setUp(self):
9 | super().setUp()
10 | self.doc = Doc.objects.create(title="test_doc", content="# tittle 1")
11 |
12 | def test_doc_views(self):
13 | testing_view_list = [
14 | TestingGetContextView(
15 | url='service_catalog:doc_list',
16 | perm_str_list=['service_catalog.list_doc'],
17 | ),
18 | TestingGetContextView(
19 | url='service_catalog:doc_details',
20 | perm_str_list=['service_catalog.view_doc'],
21 | url_kwargs={'pk': self.doc.id}
22 | ),
23 |
24 | ]
25 | self.run_permissions_tests(testing_view_list)
--------------------------------------------------------------------------------
/service_catalog/api/serializers/approval_workflow_state_serializer.py:
--------------------------------------------------------------------------------
1 | from rest_framework.relations import PrimaryKeyRelatedField
2 | from rest_framework.serializers import ModelSerializer
3 |
4 | from service_catalog.api.serializers.approval_step_state_serializer import ApprovalStepStateSerializer
5 | from service_catalog.models import ApprovalWorkflowState
6 |
7 |
8 | class ApprovalWorkflowStateSerializer(ModelSerializer):
9 | approval_workflow = PrimaryKeyRelatedField(read_only=True)
10 | current_step = PrimaryKeyRelatedField(read_only=True)
11 |
12 | class Meta:
13 | model = ApprovalWorkflowState
14 | fields = ['id', 'approval_workflow', 'approval_step_states', 'current_step']
15 |
16 | def __init__(self, *args, **kwargs):
17 | super(ApprovalWorkflowStateSerializer, self).__init__(*args, **kwargs)
18 | self.fields["approval_step_states"] = ApprovalStepStateSerializer(many=True,
19 | user=self.context.get("user"))
20 |
--------------------------------------------------------------------------------
/templates/403.html:
--------------------------------------------------------------------------------
1 | {% extends "base.html" %}
2 |
3 | {% block content %}
4 |
5 |
7 |
8 |
9 |
403
10 |
11 |
Access denied
12 |
13 | {% if exception %}
14 | {{ exception }}
15 | {% else %}
16 | The page you are trying to access has restricted access.
17 | {% endif %}
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 | {% endblock %}
26 |
--------------------------------------------------------------------------------