1919 PulpHTTPError ,
2020 PulpNoWait ,
2121 UnsafeCallError ,
22+ ValidationError ,
2223)
2324from pulp_glue .common .i18n import get_translation
2425from pulp_glue .common .openapi import METHODS , OpenAPI
@@ -61,6 +62,11 @@ def _inner(f: T) -> T:
6162]
6263
6364href_regex = re .compile (r"\/([a-z0-9-_]+\/)+" , flags = re .IGNORECASE )
65+ # Be careful model in this regex differs from resource_type in others.
66+ # model: "file.repository" ; resource_type: "file"
67+ prn_regex = re .compile (
68+ r"^prn:(?P<plugin>[a-z][a-z0-9-_]*)\.(?P<model>[a-z][a-z0-9_]*):(?P<pulp_id>[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})$" , # noqa: E501
69+ )
6470
6571
6672class PreprocessedEntityDefinition (dict [str , t .Any ]):
@@ -548,7 +554,8 @@ def call(
548554 task_href = result ["task" ]
549555 result = self .api .call ("tasks_read" , parameters = {"task_href" : task_href })
550556 self .echo (
551- _ ("Started background task {task_href}" ).format (task_href = task_href ), err = True
557+ _ ("Started background task {task_href}" ).format (task_href = task_href ),
558+ err = True ,
552559 )
553560 if not non_blocking :
554561 result = self .wait_for_task (result )
@@ -672,7 +679,8 @@ def wait_for_task_group(self, task_group: EntityDefinition) -> t.Any:
672679 time .sleep (1 )
673680 self .echo ("." , nl = False , err = True )
674681 task_group = self .api .call (
675- "task_groups_read" , parameters = {"task_group_href" : task_group ["pulp_href" ]}
682+ "task_groups_read" ,
683+ parameters = {"task_group_href" : task_group ["pulp_href" ]},
676684 )
677685 except KeyboardInterrupt :
678686 raise PulpNoWait (
@@ -713,6 +721,18 @@ def needs_plugin(
713721 # Schedule for later checking
714722 self ._needed_plugins .append (plugin_requirement )
715723
724+ def resolve_prn (self , prn : str ) -> "PulpEntityContext" :
725+ match = prn_regex .fullmatch (prn )
726+ if match is None :
727+ raise ValidationError ("Not a PRN." )
728+ plugin = match .group ("plugin" )
729+ model = match .group ("model" )
730+ pulp_id = match .group ("pulp_id" )
731+ if (ctx_class := PulpEntityContext .PRN_TYPE_REGISTRY .get (f"{ plugin } :{ model } " )) is not None :
732+ result = ctx_class .from_pulp_id (self , pulp_id )
733+ return result
734+ raise ValidationError ("Resource type unknown." )
735+
716736
717737class PulpViewSetContext :
718738 """
@@ -815,6 +835,17 @@ class PulpEntityContext(PulpViewSetContext):
815835 """
816836 HREF_PATTERN : str
817837 """Regular expression with capture groups for 'plugin' and 'resource_type' to match URIs."""
838+ HREF_TEMPLATE : str
839+
840+ PLUGIN : t .ClassVar [str ]
841+ RESOURCE_TYPE : t .ClassVar [str ]
842+ MODEL : t .ClassVar [str ]
843+ PRN_TYPE_REGISTRY : t .Final [dict [str , t .Type ["PulpEntityContext" ]]] = {}
844+
845+ def __init_subclass__ (cls , ** kwargs : t .Any ) -> None :
846+ super ().__init_subclass__ (** kwargs )
847+ if hasattr (cls , "PLUGIN" ) and hasattr (cls , "MODEL" ):
848+ cls .PRN_TYPE_REGISTRY [f"{ cls .PLUGIN } :{ cls .MODEL } " ] = cls
818849
819850 # Hidden values for the lazy entity lookup
820851 _entity : EntityDefinition | None
@@ -887,6 +918,15 @@ def pulp_href(self, value: str) -> None:
887918 self ._entity_lookup = {"pulp_href" : value }
888919 self ._entity = None
889920
921+ @classmethod
922+ def from_pulp_id (cls , pulp_ctx : PulpContext , pulp_id : str ) -> "t.Self" :
923+ if hasattr (cls , "HREF_TEMPLATE" ):
924+ return cls (
925+ pulp_ctx ,
926+ pulp_href = pulp_ctx .api_path + cls .HREF_TEMPLATE .replace ("{pulp_id}" , pulp_id ),
927+ )
928+ raise NotImplementedError ("Subclasses should implement this or provide a HREF_TEMPLATE." )
929+
890930 @property
891931 def tangible (self ) -> bool :
892932 """Indicate whether an entity is available or specified by search parameters."""
@@ -1003,7 +1043,8 @@ def _list(self, limit: int, offset: int, parameters: dict[str, t.Any]) -> list[t
10031043 pass
10041044 else :
10051045 self .pulp_ctx .echo (
1006- _ ("Not all {count} entries were shown." ).format (count = stats ["count" ]), err = True
1046+ _ ("Not all {count} entries were shown." ).format (count = stats ["count" ]),
1047+ err = True ,
10071048 )
10081049 return entities
10091050
@@ -1101,7 +1142,8 @@ def create(
11011142 h
11021143 for h in result ["created_resources" ]
11031144 if re .match (
1104- re .escape (self .pulp_ctx .api_path ) + self .HREF_PATTERN , h
1145+ re .escape (self .pulp_ctx .api_path ) + self .HREF_PATTERN ,
1146+ h ,
11051147 )
11061148 )
11071149 )
@@ -1229,7 +1271,9 @@ def unset_label(self, key: str, non_blocking: bool = False) -> t.Any:
12291271 if self .pulp_ctx .has_plugin (PluginRequirement ("core" , specifier = ">=3.34.0" )):
12301272 try :
12311273 return self .call (
1232- "unset_label" , parameters = {self .HREF : self .pulp_href }, body = {"key" : key }
1274+ "unset_label" ,
1275+ parameters = {self .HREF : self .pulp_href },
1276+ body = {"key" : key },
12331277 )
12341278 except PulpHTTPError as e :
12351279 if e .status_code != 403 :
@@ -1382,6 +1426,7 @@ class PulpRemoteContext(PulpEntityContext):
13821426 ENTITIES = _ ("remotes" )
13831427 ID_PREFIX = "remotes"
13841428 HREF_PATTERN = r"remotes/(?P<plugin>[\w\-_]+)/(?P<resource_type>[\w\-_]+)/"
1429+ HREF_TEMPLATE = "remotes/{plugin}/{resource_type}/{pulp_id}/"
13851430 NULLABLES = {
13861431 "ca_cert" ,
13871432 "client_cert" ,
@@ -1402,8 +1447,13 @@ class PulpRemoteContext(PulpEntityContext):
14021447 TYPE_REGISTRY : t .Final [dict [str , t .Type ["PulpRemoteContext" ]]] = {}
14031448
14041449 def __init_subclass__ (cls , ** kwargs : t .Any ) -> None :
1450+ if hasattr (cls , "PLUGIN" ) and hasattr (cls , "RESOURCE_TYPE" ):
1451+ cls .MODEL = f"{ cls .RESOURCE_TYPE } remote"
14051452 super ().__init_subclass__ (** kwargs )
14061453 if hasattr (cls , "PLUGIN" ) and hasattr (cls , "RESOURCE_TYPE" ):
1454+ cls .HREF_TEMPLATE = cls .HREF_TEMPLATE .replace ("{plugin}" , cls .PLUGIN ).replace (
1455+ "{resource_type}" , cls .RESOURCE_TYPE
1456+ )
14071457 cls .TYPE_REGISTRY [f"{ cls .PLUGIN } :{ cls .RESOURCE_TYPE } " ] = cls
14081458
14091459
@@ -1414,11 +1464,17 @@ class PulpPublicationContext(PulpEntityContext):
14141464 ENTITIES = _ ("publications" )
14151465 ID_PREFIX = "publications"
14161466 HREF_PATTERN = r"publications/(?P<plugin>[\w\-_]+)/(?P<resource_type>[\w\-_]+)/"
1467+ HREF_TEMPLATE = "publications/{plugin}/{resource_type}/{pulp_id}/"
14171468 TYPE_REGISTRY : t .Final [dict [str , t .Type ["PulpPublicationContext" ]]] = {}
14181469
14191470 def __init_subclass__ (cls , ** kwargs : t .Any ) -> None :
1471+ if hasattr (cls , "PLUGIN" ) and hasattr (cls , "RESOURCE_TYPE" ):
1472+ cls .MODEL = f"{ cls .RESOURCE_TYPE } publication"
14201473 super ().__init_subclass__ (** kwargs )
14211474 if hasattr (cls , "PLUGIN" ) and hasattr (cls , "RESOURCE_TYPE" ):
1475+ cls .HREF_TEMPLATE = cls .HREF_TEMPLATE .replace ("{plugin}" , cls .PLUGIN ).replace (
1476+ "{resource_type}" , cls .RESOURCE_TYPE
1477+ )
14221478 cls .TYPE_REGISTRY [f"{ cls .PLUGIN } :{ cls .RESOURCE_TYPE } " ] = cls
14231479
14241480 def list (self , limit : int , offset : int , parameters : dict [str , t .Any ]) -> list [t .Any ]:
@@ -1436,12 +1492,24 @@ class PulpDistributionContext(PulpEntityContext):
14361492 ENTITIES = _ ("distributions" )
14371493 ID_PREFIX = "distributions"
14381494 HREF_PATTERN = r"distributions/(?P<plugin>[\w\-_]+)/(?P<resource_type>[\w\-_]+)/"
1439- NULLABLES = {"content_guard" , "publication" , "remote" , "repository" , "repository_version" }
1495+ HREF_TEMPLATE = "distributions/{plugin}/{resource_type}/{pulp_id}/"
1496+ NULLABLES = {
1497+ "content_guard" ,
1498+ "publication" ,
1499+ "remote" ,
1500+ "repository" ,
1501+ "repository_version" ,
1502+ }
14401503 TYPE_REGISTRY : t .Final [dict [str , t .Type ["PulpDistributionContext" ]]] = {}
14411504
14421505 def __init_subclass__ (cls , ** kwargs : t .Any ) -> None :
1506+ if hasattr (cls , "PLUGIN" ) and hasattr (cls , "RESOURCE_TYPE" ):
1507+ cls .MODEL = f"{ cls .RESOURCE_TYPE } distribution"
14431508 super ().__init_subclass__ (** kwargs )
14441509 if hasattr (cls , "PLUGIN" ) and hasattr (cls , "RESOURCE_TYPE" ):
1510+ cls .HREF_TEMPLATE = cls .HREF_TEMPLATE .replace ("{plugin}" , cls .PLUGIN ).replace (
1511+ "{resource_type}" , cls .RESOURCE_TYPE
1512+ )
14451513 cls .TYPE_REGISTRY [f"{ cls .PLUGIN } :{ cls .RESOURCE_TYPE } " ] = cls
14461514
14471515
@@ -1511,14 +1579,20 @@ class PulpRepositoryContext(PulpEntityContext):
15111579 ENTITY = _ ("repository" )
15121580 ENTITIES = _ ("repositories" )
15131581 HREF_PATTERN = r"repositories/(?P<plugin>[\w\-_]+)/(?P<resource_type>[\w\-_]+)/"
1582+ HREF_TEMPLATE = "repositories/{plugin}/{resource_type}/{pulp_id}/"
15141583 ID_PREFIX = "repositories"
15151584 VERSION_CONTEXT : t .ClassVar [t .Type [PulpRepositoryVersionContext ]] = PulpRepositoryVersionContext
15161585 NULLABLES = {"description" , "remote" , "retain_repo_versions" }
15171586 TYPE_REGISTRY : t .Final [dict [str , t .Type ["PulpRepositoryContext" ]]] = {}
15181587
15191588 def __init_subclass__ (cls , ** kwargs : t .Any ) -> None :
1589+ if hasattr (cls , "PLUGIN" ) and hasattr (cls , "RESOURCE_TYPE" ):
1590+ cls .MODEL = f"{ cls .RESOURCE_TYPE } repository"
15201591 super ().__init_subclass__ (** kwargs )
15211592 if hasattr (cls , "PLUGIN" ) and hasattr (cls , "RESOURCE_TYPE" ):
1593+ cls .HREF_TEMPLATE = cls .HREF_TEMPLATE .replace ("{plugin}" , cls .PLUGIN ).replace (
1594+ "{resource_type}" , cls .RESOURCE_TYPE
1595+ )
15221596 cls .TYPE_REGISTRY [f"{ cls .PLUGIN } :{ cls .RESOURCE_TYPE } " ] = cls
15231597
15241598 def get_version_context (
@@ -1633,11 +1707,17 @@ class PulpContentContext(PulpEntityContext):
16331707 ENTITIES = _ ("content" )
16341708 ID_PREFIX = "content"
16351709 HREF_PATTERN = r"content/(?P<plugin>[\w\-_]+)/(?P<resource_type>[\w\-_]+)/"
1710+ HREF_TEMPLATE = "content/{plugin}/{resource_type}/{pulp_id}/"
16361711 TYPE_REGISTRY : t .Final [dict [str , t .Type ["PulpContentContext" ]]] = {}
16371712
16381713 def __init_subclass__ (cls , ** kwargs : t .Any ) -> None :
1714+ if hasattr (cls , "PLUGIN" ) and hasattr (cls , "RESOURCE_TYPE" ):
1715+ cls .MODEL = f"{ cls .RESOURCE_TYPE } content"
16391716 super ().__init_subclass__ (** kwargs )
16401717 if hasattr (cls , "PLUGIN" ) and hasattr (cls , "RESOURCE_TYPE" ):
1718+ cls .HREF_TEMPLATE = cls .HREF_TEMPLATE .replace ("{plugin}" , cls .PLUGIN ).replace (
1719+ "{resource_type}" , cls .RESOURCE_TYPE
1720+ )
16411721 cls .TYPE_REGISTRY [f"{ cls .PLUGIN } :{ cls .RESOURCE_TYPE } " ] = cls
16421722
16431723 def __init__ (
@@ -1743,12 +1823,18 @@ class PulpACSContext(PulpEntityContext):
17431823 ENTITY = _ ("ACS" )
17441824 ENTITIES = _ ("ACSes" )
17451825 HREF_PATTERN = r"acs/(?P<plugin>[\w\-_]+)/(?P<resource_type>[\w\-_]+)/"
1826+ HREF_TEMPLATE = "acs/{plugin}/{resource_type}/{pulp_id}/"
17461827 ID_PREFIX = "acs"
17471828 TYPE_REGISTRY : t .Final [dict [str , t .Type ["PulpACSContext" ]]] = {}
17481829
17491830 def __init_subclass__ (cls , ** kwargs : t .Any ) -> None :
1831+ if hasattr (cls , "PLUGIN" ) and hasattr (cls , "RESOURCE_TYPE" ):
1832+ cls .MODEL = f"{ cls .RESOURCE_TYPE } acs"
17501833 super ().__init_subclass__ (** kwargs )
17511834 if hasattr (cls , "PLUGIN" ) and hasattr (cls , "RESOURCE_TYPE" ):
1835+ cls .HREF_TEMPLATE = cls .HREF_TEMPLATE .replace ("{plugin}" , cls .PLUGIN ).replace (
1836+ "{resource_type}" , cls .RESOURCE_TYPE
1837+ )
17521838 cls .TYPE_REGISTRY [f"{ cls .PLUGIN } :{ cls .RESOURCE_TYPE } " ] = cls
17531839
17541840 def refresh (self , href : str | None = None ) -> t .Any :
@@ -1762,12 +1848,18 @@ class PulpContentGuardContext(PulpEntityContext):
17621848 ENTITIES = "content guards"
17631849 ID_PREFIX = "contentguards"
17641850 HREF_PATTERN = r"contentguards/(?P<plugin>[\w\-_]+)/(?P<resource_type>[\w\-_]+)/"
1851+ HREF_TEMPLATE = "contentguards/{plugin}/{resource_type}/{pulp_id}/"
17651852 NULLABLES = {"description" }
17661853 TYPE_REGISTRY : t .Final [dict [str , t .Type ["PulpContentGuardContext" ]]] = {}
17671854
17681855 def __init_subclass__ (cls , ** kwargs : t .Any ) -> None :
1856+ if hasattr (cls , "PLUGIN" ) and hasattr (cls , "RESOURCE_TYPE" ):
1857+ cls .MODEL = f"{ cls .RESOURCE_TYPE } contentguard"
17691858 super ().__init_subclass__ (** kwargs )
17701859 if hasattr (cls , "PLUGIN" ) and hasattr (cls , "RESOURCE_TYPE" ):
1860+ cls .HREF_TEMPLATE = cls .HREF_TEMPLATE .replace ("{plugin}" , cls .PLUGIN ).replace (
1861+ "{resource_type}" , cls .RESOURCE_TYPE
1862+ )
17711863 cls .TYPE_REGISTRY [f"{ cls .PLUGIN } :{ cls .RESOURCE_TYPE } " ] = cls
17721864
17731865
0 commit comments