2025-02-05 13:43:43 +01:00
|
|
|
#!/usr/bin/python
|
|
|
|
# coding: utf-8 -*-
|
|
|
|
|
|
|
|
"""
|
|
|
|
CVP Uploader content
|
|
|
|
"""
|
|
|
|
|
|
|
|
import os
|
|
|
|
from dataclasses import dataclass
|
2025-02-05 13:50:07 +01:00
|
|
|
from typing import Any, List, Optional
|
|
|
|
|
2025-02-05 13:43:43 +01:00
|
|
|
from cvprac.cvp_client import CvpClient
|
|
|
|
from cvprac.cvp_client_errors import CvpLoginError
|
2025-02-05 13:50:07 +01:00
|
|
|
from loguru import logger
|
2025-02-05 13:43:43 +01:00
|
|
|
|
|
|
|
# from eos_downloader.tools import exc_to_str
|
|
|
|
|
|
|
|
# logger = logging.getLogger(__name__)
|
|
|
|
|
|
|
|
|
|
|
|
@dataclass
|
|
|
|
class CvpAuthenticationItem:
|
|
|
|
"""
|
2025-02-05 13:50:07 +01:00
|
|
|
Data structure to represent Cloudvision Authentication
|
2025-02-05 13:43:43 +01:00
|
|
|
"""
|
2025-02-05 13:50:07 +01:00
|
|
|
|
2025-02-05 13:43:43 +01:00
|
|
|
server: str
|
|
|
|
port: int = 443
|
|
|
|
token: Optional[str] = None
|
|
|
|
timeout: int = 1200
|
|
|
|
validate_cert: bool = False
|
|
|
|
|
|
|
|
|
2025-02-05 13:50:07 +01:00
|
|
|
class Filer:
|
2025-02-05 13:43:43 +01:00
|
|
|
# pylint: disable=too-few-public-methods
|
|
|
|
"""
|
|
|
|
Filer Helper for file management
|
|
|
|
"""
|
2025-02-05 13:50:07 +01:00
|
|
|
|
2025-02-05 13:43:43 +01:00
|
|
|
def __init__(self, path: str) -> None:
|
|
|
|
self.file_exist = False
|
2025-02-05 13:50:07 +01:00
|
|
|
self.filename = ""
|
|
|
|
self.absolute_path = ""
|
2025-02-05 13:43:43 +01:00
|
|
|
self.relative_path = path
|
|
|
|
if os.path.exists(path):
|
|
|
|
self.file_exist = True
|
|
|
|
self.filename = os.path.basename(path)
|
|
|
|
self.absolute_path = os.path.realpath(path)
|
|
|
|
|
|
|
|
def __repr__(self) -> str:
|
2025-02-05 13:50:07 +01:00
|
|
|
return self.absolute_path if self.file_exist else ""
|
2025-02-05 13:43:43 +01:00
|
|
|
|
|
|
|
|
2025-02-05 13:50:07 +01:00
|
|
|
class CvFeatureManager:
|
2025-02-05 13:43:43 +01:00
|
|
|
"""
|
|
|
|
CvFeatureManager Object to interect with Cloudvision
|
|
|
|
"""
|
2025-02-05 13:50:07 +01:00
|
|
|
|
2025-02-05 13:43:43 +01:00
|
|
|
def __init__(self, authentication: CvpAuthenticationItem) -> None:
|
|
|
|
"""
|
|
|
|
__init__ Class Creator
|
|
|
|
|
|
|
|
Parameters
|
|
|
|
----------
|
|
|
|
authentication : CvpAuthenticationItem
|
|
|
|
Authentication information to use to connect to Cloudvision
|
|
|
|
"""
|
|
|
|
self._authentication = authentication
|
|
|
|
# self._cv_instance = CvpClient()
|
|
|
|
self._cv_instance = self._connect(authentication=authentication)
|
|
|
|
self._cv_images = self.__get_images()
|
|
|
|
# self._cv_bundles = self.__get_bundles()
|
|
|
|
|
|
|
|
def _connect(self, authentication: CvpAuthenticationItem) -> CvpClient:
|
|
|
|
"""
|
|
|
|
_connect Connection management
|
|
|
|
|
|
|
|
Parameters
|
|
|
|
----------
|
|
|
|
authentication : CvpAuthenticationItem
|
|
|
|
Authentication information to use to connect to Cloudvision
|
|
|
|
|
|
|
|
Returns
|
|
|
|
-------
|
|
|
|
CvpClient
|
|
|
|
cvprac session to cloudvision
|
|
|
|
"""
|
|
|
|
client = CvpClient()
|
|
|
|
if authentication.token is not None:
|
|
|
|
try:
|
|
|
|
client.connect(
|
|
|
|
nodes=[authentication.server],
|
2025-02-05 13:50:07 +01:00
|
|
|
username="",
|
|
|
|
password="",
|
2025-02-05 13:43:43 +01:00
|
|
|
api_token=authentication.token,
|
|
|
|
is_cvaas=True,
|
|
|
|
port=authentication.port,
|
|
|
|
cert=authentication.validate_cert,
|
2025-02-05 13:50:07 +01:00
|
|
|
request_timeout=authentication.timeout,
|
2025-02-05 13:43:43 +01:00
|
|
|
)
|
|
|
|
except CvpLoginError as error_data:
|
2025-02-05 13:50:07 +01:00
|
|
|
logger.error(
|
|
|
|
f"Cannot connect to Cloudvision server {authentication.server}"
|
|
|
|
)
|
|
|
|
logger.debug(f"Error message: {error_data}")
|
|
|
|
logger.info("connected to Cloudvision server")
|
|
|
|
logger.debug(f"Connection info: {authentication}")
|
2025-02-05 13:43:43 +01:00
|
|
|
return client
|
|
|
|
|
|
|
|
def __get_images(self) -> List[Any]:
|
|
|
|
"""
|
|
|
|
__get_images Collect information about images on Cloudvision
|
|
|
|
|
|
|
|
Returns
|
|
|
|
-------
|
|
|
|
dict
|
|
|
|
Fact returned by Cloudvision
|
|
|
|
"""
|
|
|
|
images = []
|
2025-02-05 13:50:07 +01:00
|
|
|
logger.debug(" -> Collecting images")
|
|
|
|
images = self._cv_instance.api.get_images()["data"]
|
2025-02-05 13:43:43 +01:00
|
|
|
return images if self.__check_api_result(images) else []
|
|
|
|
|
|
|
|
# def __get_bundles(self):
|
|
|
|
# """
|
|
|
|
# __get_bundles [Not In use] Collect information about bundles on Cloudvision
|
|
|
|
|
|
|
|
# Returns
|
|
|
|
# -------
|
|
|
|
# dict
|
|
|
|
# Fact returned by Cloudvision
|
|
|
|
# """
|
|
|
|
# bundles = []
|
|
|
|
# logger.debug(' -> Collecting images bundles')
|
|
|
|
# bundles = self._cv_instance.api.get_image_bundles()['data']
|
|
|
|
# # bundles = self._cv_instance.post(url='/cvpservice/image/getImageBundles.do?queryparam=&startIndex=0&endIndex=0')['data']
|
|
|
|
# return bundles if self.__check_api_result(bundles) else None
|
|
|
|
|
|
|
|
def __check_api_result(self, arg0: Any) -> bool:
|
|
|
|
"""
|
|
|
|
__check_api_result Check API calls return content
|
|
|
|
|
|
|
|
Parameters
|
|
|
|
----------
|
|
|
|
arg0 : any
|
|
|
|
Element to test
|
|
|
|
|
|
|
|
Returns
|
|
|
|
-------
|
|
|
|
bool
|
|
|
|
True if data are correct False in other cases
|
|
|
|
"""
|
|
|
|
logger.debug(arg0)
|
|
|
|
return len(arg0) > 0
|
|
|
|
|
|
|
|
def _does_image_exist(self, image_name: str) -> bool:
|
|
|
|
"""
|
|
|
|
_does_image_exist Check if an image is referenced in Cloudvision facts
|
|
|
|
|
|
|
|
Parameters
|
|
|
|
----------
|
|
|
|
image_name : str
|
|
|
|
Name of the image to search for
|
|
|
|
|
|
|
|
Returns
|
|
|
|
-------
|
|
|
|
bool
|
|
|
|
True if present
|
|
|
|
"""
|
2025-02-05 13:50:07 +01:00
|
|
|
return (
|
|
|
|
any(image_name == image["name"] for image in self._cv_images)
|
|
|
|
if isinstance(self._cv_images, list)
|
|
|
|
else False
|
|
|
|
)
|
2025-02-05 13:43:43 +01:00
|
|
|
|
|
|
|
def _does_bundle_exist(self, bundle_name: str) -> bool:
|
|
|
|
# pylint: disable=unused-argument
|
|
|
|
"""
|
|
|
|
_does_bundle_exist Check if an image is referenced in Cloudvision facts
|
|
|
|
|
|
|
|
Returns
|
|
|
|
-------
|
|
|
|
bool
|
|
|
|
True if present
|
|
|
|
"""
|
|
|
|
# return any(bundle_name == bundle['name'] for bundle in self._cv_bundles)
|
|
|
|
return False
|
|
|
|
|
|
|
|
def upload_image(self, image_path: str) -> bool:
|
|
|
|
"""
|
|
|
|
upload_image Upload an image to Cloudvision server
|
|
|
|
|
|
|
|
Parameters
|
|
|
|
----------
|
|
|
|
image_path : str
|
|
|
|
Path to the local file to upload
|
|
|
|
|
|
|
|
Returns
|
|
|
|
-------
|
|
|
|
bool
|
|
|
|
True if succeeds
|
|
|
|
"""
|
|
|
|
image_item = Filer(path=image_path)
|
|
|
|
if image_item.file_exist is False:
|
2025-02-05 13:50:07 +01:00
|
|
|
logger.error(f"File not found: {image_item.relative_path}")
|
2025-02-05 13:43:43 +01:00
|
|
|
return False
|
2025-02-05 13:50:07 +01:00
|
|
|
logger.info(f"File path for image: {image_item}")
|
2025-02-05 13:43:43 +01:00
|
|
|
if self._does_image_exist(image_name=image_item.filename):
|
2025-02-05 13:50:07 +01:00
|
|
|
logger.error(
|
|
|
|
"Image found in Cloudvision , Please delete it before running this script"
|
|
|
|
)
|
2025-02-05 13:43:43 +01:00
|
|
|
return False
|
|
|
|
try:
|
2025-02-05 13:50:07 +01:00
|
|
|
upload_result = self._cv_instance.api.add_image(
|
|
|
|
filepath=image_item.absolute_path
|
|
|
|
)
|
2025-02-05 13:43:43 +01:00
|
|
|
except Exception as e: # pylint: disable=broad-exception-caught
|
2025-02-05 13:50:07 +01:00
|
|
|
logger.error("An error occurred during upload, check CV connection")
|
|
|
|
logger.error(f"Exception message is: {e}")
|
2025-02-05 13:43:43 +01:00
|
|
|
return False
|
2025-02-05 13:50:07 +01:00
|
|
|
logger.debug(f"Upload Result is : {upload_result}")
|
2025-02-05 13:43:43 +01:00
|
|
|
return True
|
|
|
|
|
|
|
|
def build_image_list(self, image_list: List[str]) -> List[Any]:
|
|
|
|
"""
|
|
|
|
Builds a list of the image data structures, for a given list of image names.
|
|
|
|
Parameters
|
|
|
|
----------
|
|
|
|
image_list : list
|
|
|
|
List of software image names
|
|
|
|
Returns
|
|
|
|
-------
|
|
|
|
List:
|
|
|
|
Returns a list of images, with complete data or None in the event of failure
|
|
|
|
"""
|
|
|
|
internal_image_list = []
|
|
|
|
image_data = None
|
|
|
|
success = True
|
|
|
|
|
|
|
|
for entry in image_list:
|
|
|
|
for image in self._cv_images:
|
|
|
|
if image["imageFileName"] == entry:
|
|
|
|
image_data = image
|
|
|
|
|
|
|
|
if image_data is not None:
|
|
|
|
internal_image_list.append(image_data)
|
|
|
|
image_data = None
|
|
|
|
else:
|
|
|
|
success = False
|
|
|
|
|
|
|
|
return internal_image_list if success else []
|
|
|
|
|
|
|
|
def create_bundle(self, name: str, images_name: List[str]) -> bool:
|
|
|
|
"""
|
|
|
|
create_bundle Create a bundle with a list of images.
|
|
|
|
|
|
|
|
Parameters
|
|
|
|
----------
|
|
|
|
name : str
|
|
|
|
Name of the bundle
|
|
|
|
images_name : List[str]
|
|
|
|
List of images available on Cloudvision
|
|
|
|
|
|
|
|
Returns
|
|
|
|
-------
|
|
|
|
bool
|
|
|
|
True if succeeds
|
|
|
|
"""
|
2025-02-05 13:50:07 +01:00
|
|
|
logger.debug(
|
|
|
|
f"Init creation of an image bundle {name} with following images {images_name}"
|
|
|
|
)
|
2025-02-05 13:43:43 +01:00
|
|
|
all_images_present: List[bool] = []
|
|
|
|
self._cv_images = self.__get_images()
|
|
|
|
all_images_present.extend(
|
2025-02-05 13:50:07 +01:00
|
|
|
self._does_image_exist(image_name=image_name) for image_name in images_name
|
2025-02-05 13:43:43 +01:00
|
|
|
)
|
|
|
|
# Bundle Create
|
|
|
|
if self._does_bundle_exist(bundle_name=name) is False:
|
2025-02-05 13:50:07 +01:00
|
|
|
logger.debug(
|
|
|
|
f"Creating image bundle {name} with following images {images_name}"
|
|
|
|
)
|
2025-02-05 13:43:43 +01:00
|
|
|
images_data = self.build_image_list(image_list=images_name)
|
|
|
|
if images_data is not None:
|
2025-02-05 13:50:07 +01:00
|
|
|
logger.debug("Images information: {images_data}")
|
2025-02-05 13:43:43 +01:00
|
|
|
try:
|
2025-02-05 13:50:07 +01:00
|
|
|
data = self._cv_instance.api.save_image_bundle(
|
|
|
|
name=name, images=images_data
|
|
|
|
)
|
2025-02-05 13:43:43 +01:00
|
|
|
except Exception as e: # pylint: disable=broad-exception-caught
|
2025-02-05 13:50:07 +01:00
|
|
|
logger.critical(f"{e}")
|
2025-02-05 13:43:43 +01:00
|
|
|
else:
|
|
|
|
logger.debug(data)
|
|
|
|
return True
|
2025-02-05 13:50:07 +01:00
|
|
|
logger.critical("No data found for images")
|
2025-02-05 13:43:43 +01:00
|
|
|
return False
|