This commit introduces the new dcagent package. It is comprised of a
periodic process that queries the necessary endpoints to gather the
audit data and an API running on port 8325 (internal) and 8326 (admin).
The api only has one endpoint /v1/dcaudit that accepts only PATCH and
will respond with 'in-sync' or 'out-of-sync' for dcmanager-audit based
on the RegionOne data provided or will return the subcloud data for the
requested endpoints for dcorch-audit.
The agent also supports a key 'use_cache' to be sent in the payload
that will determine if it should use the cache data gathered by the
periodic process or get new information on the fly.
Example of payload using cached data:
{
"base_audit": "",
"firmware_audit": "<regionone-audit-data>",
"kubernetes_audit": "<regionone-audit-data>",
"kube_rootca_audit" : "<regionone-audit-data>",
"software_audit": "<regionone-audit-data>"
}
Example of payload requesting new information:
{
"certificates": "",
"iuser": "",
"fernet_repo": "",
"use_cache": "false"
}
NOTES:
- As patch and load audits will be deprecated in the next major
release, no effort was made to integrate both patch and load audit
to dcagent.
- All tests described below were executed applying [1] as well,
to avoid retesting.
[1]: https://review.opendev.org/c/starlingx/distcloud/+/923351
Test plan:
- PASS: Run dcmanager audit with dcagent. Verify only one call is
made to audit the subcloud and the response include the
correct sync status.
- PASS: Run dcmanager audit without dcagent. Verify the audit
works as expected querying each individual endpoint.
Story: 2011106
Task: 50559
Change-Id: I1820ca9688d5d05f8712f9a42f6012f2ec3e2d8a
Signed-off-by: Victor Romano <victor.gluzromano@windriver.com>
103 lines
3.0 KiB
Python
103 lines
3.0 KiB
Python
#
|
|
# Copyright (c) 2024 Wind River Systems, Inc.
|
|
#
|
|
# SPDX-License-Identifier: Apache-2.0
|
|
#
|
|
|
|
import abc
|
|
|
|
from pecan import expose
|
|
from pecan import request
|
|
|
|
import dcagent.common.context as k_context
|
|
|
|
|
|
def extract_context_from_environ():
|
|
context_params = {
|
|
"auth_token": "HTTP_X_AUTH_TOKEN",
|
|
"user": "HTTP_X_USER_ID",
|
|
"project": "HTTP_X_TENANT_ID",
|
|
"user_name": "HTTP_X_USER_NAME",
|
|
"tenant_name": "HTTP_X_PROJECT_NAME",
|
|
"domain": "HTTP_X_DOMAIN_ID",
|
|
"roles": "HTTP_X_ROLE",
|
|
"user_domain": "HTTP_X_USER_DOMAIN_ID",
|
|
"project_domain": "HTTP_X_PROJECT_DOMAIN_ID",
|
|
"request_id": "openstack.request_id",
|
|
}
|
|
|
|
environ = request.environ
|
|
|
|
for key, val in context_params.items():
|
|
context_params[key] = environ.get(val)
|
|
role = environ.get("HTTP_X_ROLE")
|
|
|
|
context_params["is_admin"] = "admin" in role.split(",")
|
|
return k_context.RequestContext(**context_params)
|
|
|
|
|
|
def extract_credentials_for_policy():
|
|
context_paras = {"project_name": "HTTP_X_PROJECT_NAME", "roles": "HTTP_X_ROLE"}
|
|
environ = request.environ
|
|
for key, val in context_paras.items():
|
|
context_paras[key] = environ.get(val)
|
|
context_paras["roles"] = context_paras["roles"].split(",")
|
|
return context_paras
|
|
|
|
|
|
def _get_pecan_data(obj):
|
|
return getattr(obj, "_pecan", {})
|
|
|
|
|
|
def _is_exposed(obj):
|
|
return getattr(obj, "exposed", False)
|
|
|
|
|
|
def _is_generic(obj):
|
|
data = _get_pecan_data(obj)
|
|
return "generic" in data.keys()
|
|
|
|
|
|
def _is_generic_handler(obj):
|
|
data = _get_pecan_data(obj)
|
|
return "generic_handler" in data.keys()
|
|
|
|
|
|
class GenericPathController(object, metaclass=abc.ABCMeta):
|
|
"""A controller that allows path parameters to be equal to handler names.
|
|
|
|
The _route method provides a custom route resolution that checks if the
|
|
next object is marked as generic or a generic handler, pointing to the
|
|
generic index method in case it is. Pecan will properly handle the rest
|
|
of the routing process by redirecting it to the proper method function
|
|
handler (GET, POST, PATCH, DELETE, etc.).
|
|
|
|
Useful when part of the URL contains path parameters that might have
|
|
the same name as an already defined exposed controller method.
|
|
|
|
Requires the definition of an index method with the generator:
|
|
@expose(generic=True, ...)
|
|
|
|
Does not support nested subcontrollers.
|
|
"""
|
|
|
|
RESERVED_NAMES = ("_route", "_default", "_lookup")
|
|
|
|
@abc.abstractmethod
|
|
def index(self):
|
|
pass
|
|
|
|
@expose()
|
|
def _route(self, remainder, request):
|
|
next_url_part, rest = remainder[0], remainder[1:]
|
|
next_obj = getattr(self, next_url_part, None)
|
|
|
|
is_generic = _is_generic(next_obj) or _is_generic_handler(next_obj)
|
|
is_reserved_name = next_url_part in self.__class__.RESERVED_NAMES
|
|
|
|
if _is_exposed(next_obj) and not is_generic and not is_reserved_name:
|
|
# A non-generic exposed method with a non-reserved name
|
|
return next_obj, rest
|
|
else:
|
|
return self.index, remainder
|