o nnh@sddlmZddlZddlZddlZddlZddlZddlZddlZddl Z ddl Z ddl Z ddl m Z ddlmZmZddlmZmZddlmZmZmZmZmZddlmZddlmZdd l m!Z!dd l"m#Z#dd l"m$Z$dd l%m&Z&dd l'm(Z(m)Z)m*Z*ddl+m,Z,m-Z-ddl.m/Z/ddl0m1Z1ddl2m3Z3e/Z4e 5Z6dZ7e j8de j9hZ:ddZ;ddZe;ddZ?ddZ@Gd d!d!eZAeBd"gd#ZCGd$d%d%ZDejEGd&d'd'ZFdS)() annotationsN) HTTPStatus) BadStatusLineIncompleteRead) HTTPErrorURLError)quote urlencodeurlparseparse_qsurljoin) constants) AnsibleError) user_agent)retry_with_delays_and_condition)generate_jittered_backoff) string_types)to_bytes to_nativeto_text)open_urlprepare_multipart)Display) secure_hash_s) makedirs_safedicfdd}|S)Ncs6t|i|WdS1swYdSN) _CACHE_LOCK)argskwargsfunc=/usr/local/lib/python3.10/dist-packages/ansible/galaxy/api.pywrapped.s $zcache_lock..wrappedr#)r"r%r#r!r$ cache_lock-s r&cCsZt|tr |jtvr dSt|tr+t|dd}r+t|tr!|j}t|tt t fr+dSdS)NTorig_excF) isinstance GalaxyError http_codeRETRY_HTTP_ERROR_CODESrgetattrrreason TimeoutErrorrr) exceptionr'r#r#r$should_retry_error5s r0cr)z Wrapper to lazily initialize connection info to Galaxy and verify the API versions required are available on the endpoint. :param versions: A list of API versions that the function supports. csfdd}|S)Nc s|jstd|j|j}d|j|f}|jdks|jdkr!d}z |j|d|dd}WnFtttt fyr}z6| d sB| d rCt |d }z |j|d|dd}Wntyg}z|j d krb|d}~wwWYd}~nd}~wwd |vrtd ||jf||_| d ddi}t|dgkrd|d<||_tdd||j|jft|j}t|} | stdjdd||j|jf| dhkrtjddd|g|Ri|S)Nz'Initial connection to galaxy_server: %sz6Error when finding available api versions from %s (%s)zhttps://galaxy.ansible.comzhttps://galaxy.ansible.com/zhttps://galaxy.ansible.com/api/GETT)methoderror_context_msgcachez/apiz/api/available_versionszSTried to find galaxy API root at %s but no 'available_versions' are available on %sv1zv1/zv2/v2z1Found API version '%s' with Galaxy server %s (%s), zPGalaxy action %s requires API versions '%s' but only '%s' are available on %s %szThe v2 Ansible Galaxy API is deprecated and no longer supported. Ensure that you have configured the ansible-galaxy CLI to utilize an updated and supported version of Ansible Galaxy.z2.20version)_available_api_versionsdisplayvvvv api_servername _call_galaxyrr) ValueErrorKeyErrorendswith_urljoinr*getlistkeysjoinset intersection__name__ deprecated) selfrr n_urlr3dataerrnew_errr6common_versions)r2versionsr#r$r%Qsb    z-g_connect..decorator..wrappedr#)r2r%rT)r2r$ decoratorPsAzg_connect..decoratorr#)rTrVr#rUr$ g_connectIs CrWcCs<t|}d}z|j}Wn tyYnwd|j|pdfS)z* Gets the cache ID for the URL specified. Nz%s:%s)r portrBhostname)urlurl_inforYr#r#r$ get_cache_ids  r]cCsdd}tj|s,tdt|t|dt|dWdn1s'wYt|j }|tj @rBt dt|dSt|dd}t| d d }Wdn1s[wYzt |}Wn tyrd}Ynwt|tr|d d|krtd t|d |i}t|d d}|tt |d d Wd|S1swY|S)zR Loads the cache file requested if possible. The file must not be world writable. z/Creating Galaxy API response cache file at '%s'wiNzKGalaxy cache has world writable access (%s), ignoring it as a cache source.rbmodesurrogate_or_stricterrorsr;z:Galaxy cache file at '%s' has an invalid version, clearingwb)ospathisfiler=r>ropenchmodstatst_modeS_IWOTHwarningreadjsonloadsrBr(dictrFwriterdumps) b_cache_path cache_version cache_modefdjson_valr4r#r#r$ _load_caches:      r{cGsddd|dDS)N/css&|]}|rt|dddVqdS)rcrdr|N)rstrip).0ar#r#r$ s$z_urljoin..)rX)rI)rr#r#r$rEsrEcs eZdZdZfddZZS)r)z( Error for bad Galaxy server responses. c sHtt|||j|_||_z t|}t |}Wn t t fy+i}Ynw|j d}d|vrM|d|j}|dd}d||j||f}nPd|vr|dg} | s\ig} g} | D]#} | d pn| d pn|j} | dpud} d |j| | f}| |q`d |d | f}n|d|j}d||j|f}t||_dS)Nr|r8messagecodeUnknownz(%s (HTTP Code: %d, Message: %s Code: %s)v3redetailtitlez%(HTTP Code: %d, Message: %s Code: %s)z%s %sr9defaultz%s (HTTP Code: %d, Message: %s))superr)__init__rr*geturlr[rrprqrrAttributeErrorrBsplitrFr-appendrIrr)rN http_errorrhttp_msgerr_info url_split galaxy_msgrfull_error_msgre message_lineserror error_msg error_code message_line __class__r#r$rs8      zGalaxyError.__init__)rL __module__ __qualname____doc__r __classcell__r#r#rr$r)sr)CollectionMetadata) namespacer@ created_str modified_strc@seZdZddZdS)CollectionVersionMetadatac Cs4||_||_||_||_||_||_||_||_dS)a Contains common information about a collection on a Galaxy server to smooth through API differences for Collection and define a standard meta info for a collection. :param namespace: The namespace name. :param name: The collection name. :param version: The version that the metadata refers to. :param download_url: The URL to download the collection. :param artifact_sha256: The SHA256 of the collection artifact for later verification. :param dependencies: A dict of dependencies of the collection. :param signatures_url: The URL to the specific version of the collection. :param signatures: The list of signatures found at the signatures_url. N)rr@r; download_urlartifact_sha256 dependenciessignatures_url signatures) rNrr@r;rrrrrr#r#r$rs z"CollectionVersionMetadata.__init__N)rLrrrr#r#r#r$rs rc @seZdZdZdddddddeddf ddZd d Zd d Zd dZddZ e e gdddZ e edddded  dEddZdFddZeddZe dgd d!Ze dgdGd"d#Ze dgdHd$d%Ze dgdId&d'Ze dgd(d)Ze dgd*d+Ze dgd,d-Ze dgd.d/Ze dgd0d1Ze dgd2d3Ze dgd4d5Ze d6d7gd8d9Ze d6d7gdJd;d<Z e d6d7gd=d>Z!e d6d7gd?d@Z"e d6d7gdAdBZ#e d6d7gdCdDZ$dS)K GalaxyAPIzM This class is meant to be used as a API client for an Ansible Galaxy server NTFinf<c Cs||_||_||_||_||_||_||_| |_|pi|_| |_ | |_ t t j dd} t| ddtj| d|_| rcttj|jrTtdt|jt|jWdn1s^wYd|_| snt|j|_td|j|jfdS)Nrcrdirasapi.jsonzClearing cache file (%s)z$Validate TLS certificates for %s: %s)galaxyr@usernamepasswordtokenr?validate_certstimeoutr< _priority_server_timeoutrCGALAXY_CACHE_DIRrrgrhrI _b_cache_pathrexistsr=r>rremove_cacher{debug)rNrr@r[rrrravailable_api_versionsclear_response_cacheno_cachepriorityr b_cache_dirr#r#r$rs2    zGalaxyAPI.__init__cC t|jS)z3Render GalaxyAPI as a native string representation.)rr@rNr#r#r$__str__: zGalaxyAPI.__str__cCr)z9Render GalaxyAPI as a unicode/text string representation.)rr@rr#r#r$ __unicode__?rzGalaxyAPI.__unicode__cCsdj||j|j|jdS)z9Render GalaxyAPI as an inspectable string representation.z><{instance!s} "{name!s}" @ {url!s} with priority {priority!s}>)instancer@rr[)formatr@rr?rr#r#r$__repr__Ds zGalaxyAPI.__repr__cCs(t||jstS|j|jkp|j|jkS)z:Return whether the instance priority is higher than other.)r(rNotImplementedrr@)rNother_galaxy_apir#r#r$__lt__Os   zGalaxyAPI.__lt__)r7r8rcCs|jSr)r<rr#r#r$rZsz GalaxyAPI.available_api_versions()retries delay_basedelay_threshold)backoff_iteratorr0c  Cst|} t|} |s | j}t| j} |r|jr|j| i} d} d}|| vrCtj| |d| }|j tj j d}tj tj j |k}d| vpJd| v}|r|s| |}| dr{d|vrcd d dii}nd di}g|d <|d D] }|d |qo|S|d }|S|stj tj j }|tjd d 7}|| dd| |<|pi}|j|||dztd|tt|||j|||jtdd}Wn(ty}zt||d}~wty}z td|t|f|dd}~wwt|dd}zt |}Wnt!ytd|j"t|fw|rN|jrN|j| |}d}dD] }||vr,|}nq!|rJd|d<|d g}||D]}||q?|S||d <|S)Nz%Y-%m-%dT%H:%M:%SZFexpires)tzinfopageoffset paginatedz/v3/linksnextresultsr^)days)rr)requiredzCalling Galaxy at %ssafe)rPrheadersr2r http_agentfollow_redirectsz8Unknown error when attempting to call Galaxy at '%s': %sr'rcrdz5Failed to parse Galaxy response from '%s' as JSON: %s)rPrT)#r r]rhr queryr setdefaultdatetimestrptimereplacetimezoneutcnowrFr timedeltastrftime_add_auth_tokenr=r>rrrrrrr) ExceptionrrrprqrrrBr[)rNr[rrr2 auth_requiredr3r4 cache_keyr\cache_idr server_cacheiso_datetime_formatvalidris_paginated_url path_cacheresresultrespe resp_datarP paginated_keykeyrr#r#r$rA`s            zGalaxyAPI._call_galaxycCsHd|vrdS|js|rtdttj|jr"||jdSdS)N AuthorizationzMNo access token or username set. A token can be set with --api-key or at {0}.)rrrrrGALAXY_TOKEN_PATHupdater)rNrr[ token_typerr#r#r$rs  zGalaxyAPI._add_auth_tokencCsNt|jdd}|tt|jddWddS1s wYdS)Nrfrarcrd)rjrrtrrqrur)rNryr#r#r$ _set_caches"zGalaxyAPI._set_cacher7c Cst|j|jddd}td|i}zt|||jdt|jd}Wn&ty2}zt |dd}~wt yG}z t d t ||d d}~wwt t|d d }|S) z2 Retrieve an authentication token r7tokensr| github_tokenPOST)rPrr2rrz$Attempting to authenticate to galaxyNz$Unable to authenticate to galaxy: %srrcrd)rEr?rr rrrrrr)rrrrqrrrrp)rNrr[rrrrPr#r#r$ authenticates  zGalaxyAPI.authenticatecCsdt|j|jddd}|||r|ndd}|r||d<|j|t|dd}|d d r0|d S|S) z( Post an import request r7importsr|rX) github_user github_repogithub_referencealternate_role_namerrr2rN)rEr?rrAr rF)rNrr reference role_namer[rrPr#r#r$create_import_tasks  zGalaxyAPI.create_import_taskcCsdt|j|jdd}|durd||f}n|dur%|dur%d|||f}ntd||}|dS)z5 Check the status of an import task. r7rNz%s?id=%dz %s?github_user=%s&github_repo=%sz/Expected task_id or github_user and github_repor)rEr?rrrA)rNtask_idrrr[rPr#r#r$get_import_tasks zGalaxyAPI.get_import_taskcCsttt|}z|d}d|dd}|d}|r&td||fWn ty4td|wt|j |j ddd||f}| |}t |d dkrW|d dSd S) z& Find a role by name. .rz$- downloading role '%s', owned by %szAInvalid role name (%s). Specify role as format: username.rolenamer7rolesz?owner__username=%s&name=%srN) rurlquoterrrIr=rrrEr?rrAlen)rNr notifyparts user_namer[rPr#r#r$lookup_role_by_names$      zGalaxyAPI.lookup_role_by_namec Csg}zOt|j|jdd||d}||}|d}|dddu}t|j}d|j|jf}|sOt||d}||}||d7}|dddu}|r0W|SW|Styp} zt d||t | fWYd} ~ |Sd} ~ ww) z Fetch the list of related items for the given role. The url comes from the 'related' field of the role. r7rz ?page_size=50r next_linkNz%s://%s/zSUnable to retrieve role (id=%s) data (%s), but this is not fatal so we continue: %s) rEr?rrArFr schemenetlocrr=ror) rNrelatedrole_idrr[rPdoner\base_urlrr#r#r$fetch_role_relateds4     zGalaxyAPI.fetch_role_relatedc CszKt|j|jd|d}||}d|vr|d}n|}d}d|vr*|dddu}|sIt|j|d}||}||d7}|dddu}|r,|WStya}z td|t|fd}~ww) z4 Fetch the list of items specified. r7z ?page_sizerTrrNz"Failed to download the %s list: %s)rEr?rrArFrrr)rNwhatr[rPrrrr#r#r$get_list8s(    zGalaxyAPI.get_listc Kst|j|jdddd}|r|dttt|7}|dd}|dd}|dd}|d d}|rGt|trG| d }|d d |7}|r\t|tr\| d }|d d |7}|rd|d|7}|rl|d|7}| |}|S)Nr7searchr?z&autocomplete=tags platforms page_sizeauthor,z&tags_autocomplete=+z&platforms_autocomplete=z &page_size=%sz&username_autocomplete=%s) rEr?rrrrrFr(rrrIrA) rNr#r search_urlr%r&r'r(rPr#r#r$ search_rolesPs&         zGalaxyAPI.search_rolescCs>t|j|jddd}t||||d}|j||dd}|S)Nr7notification_secretsr|)sourcerrsecretrr )rEr?rr rA)rNr.rrr/r[rrPr#r#r$ add_secretnszGalaxyAPI.add_secretcCs&t|j|jdd}|j|dd}|S)Nr7r-T)rrEr?rrA)rNr[rPr#r#r$ list_secretszszGalaxyAPI.list_secretscCs.t|j|jdd|d}|j|ddd}|S)Nr7r-r|TDELETErr2r1)rN secret_idr[rPr#r#r$ remove_secretszGalaxyAPI.remove_secretcCs2t|j|jddd||f}|j|ddd}|S)Nr7 removerolez?github_user=%s&github_repo=%sTr3r4r1)rNrrr[rPr#r#r$ delete_roles  zGalaxyAPI.delete_roler8rc Cs$td||j|jft|dd}tj|s tdt|t |s-tdt|t |d}t | tjd}Wdn1sFwYt||d d d \}}|t|d }d |jvrqt|j|jd ddd}n t|j|jddd}|j|||ddd|j|jfd} | dS)z Publishes a collection to a Galaxy server and returns the import task URI. :param collection_path: The path to the collection tarball to publish. :return: The import task URI that contains the import results. z,Publishing collection artifact '%s' to %s %srcrdz2The collection path specified '%s' does not exist.zThe collection path specified '%s' is not a tarball, use 'ansible-galaxy collection build' to create a proper release artifact.r`) hash_funcNzapplication/octet-stream)filename mime_type)sha256file)z Content-typezContent-lengthr artifacts collectionsr|r8rTz+Error when publishing collection to %s (%s))rrr2rr3task)r=r@r?rrgrhrrrtarfile is_tarfilerjrrphashlibr<rrrrErA) rNcollection_pathb_collection_pathcollection_tarr< content_type b_form_datarrOrr#r#r$publish_collections<       zGalaxyAPI.publish_collectionrc Csd}d}d|jvrt|j|jdd|d}n t|j|jdd|d}td|t}d }|d ks;t||krz |j|d d d |d}Wn$tyl}z|jdkrVtd|t |WYd}~q/d}~ww| dd}| ddrzn!td||ft |t d|d}|d ks;t||ks;|dkrt dt || dgD]1} | d} | dkrtd| dq| dkrtd| dqtd| | dfq|dkrt |d d d!} t |d d"d#|} t d$| | fdS)%aH Waits until the import process on the Galaxy server has completed or the timeout is reached. :param task_id: The id of the import task to wait for. This can be parsed out of the return value for GalaxyAPI.publish_collection. :param timeout: The timeout in seconds, 0 is no timeout. waitingNrzimports/collectionsr|r8zcollection-importsz1Waiting until Galaxy import task %s has completedrrr1Tz,Error when getting import task results at %s)r2rr3r5zJGalaxy import process has not started, wait %s seconds before trying againstate finished_atzMGalaxy import process has a status of %s, wait %d seconds before trying againg?zUTimeout while waiting for the Galaxy import process to finish, check progress at '%s'messageslevelrzGalaxy import error message: %srroz!Galaxy import warning message: %szGalaxy import message: %s - %sfailedrUNKNOWN descriptionz&Unknown error, see %s for more detailsz+Galaxy import process failed: %s (Code: %s))rrEr?r=timerAr)r*vvvsleeprFminrrlowerrro) rNrrrKrPfull_urlstartwaitrrrOrrRr#r#r$wait_import_tasksh             zGalaxyAPI.wait_import_taskc Csd|jvr|jd}ddg}n |jd}ddg}t|j|d||d}d |||j|jf}|j||d }i}|D] \}} || d ||<q7t||fi|S) z Gets the collection information from the Galaxy server about a specific Collection. :param namespace: The collection namespace. :param name: The collection name. return: CollectionMetadata about the collection. r)r created_at)r updated_atr8)rcreated)rmodifiedr?r|z=Error when getting the collection info for %s.%s from %s (%s))r3N)rrEr?r@rArFr) rNrr@api_path field_mapinfo_urlr3rPmetadata api_fieldr#r#r$get_collection_metadatas$   z!GalaxyAPI.get_collection_metadatac Cs|jd|jd}|j|d||d|dg}t|}d||||j|jf}|j||dd}||d p7g} t|d d |d d |d |d|dd|dd|d| S)at Gets the collection information from the Galaxy server about a specific Collection version. :param namespace: The collection namespace. :param name: The collection name. :param version: Version of the collection to get the information for. :return: CollectionVersionMetadata about the collection at the version requested. rr8r?rTr|HError when getting collection version metadata for %s.%s:%s from %s (%s)Tr3r4rrr@ collectionr;rartifactr<rcrhref)rrFr?rEr@rArr rNrr@r;r` url_pathsn_collection_urlr3rPrr#r#r$get_collection_version_metadata s z)GalaxyAPI.get_collection_version_metadatac Csd}d|jvr|jd}ddg}d}n|jd}dg}d|jvr"dnd}t|j|d ||d d |tf}t|}|j} |jr|jt|i} | d i} z | ||j } Wnt yo} z| j d krcgWYd} ~ Sd} ~ ww| d||fd}|| kr| | d||f<|j| vr| | =|d|||j|jf}z |j||d| d}Wnt y} z| j d krgWYd} ~ Sd} ~ wwd|vrd}nd}g} |dd||D7}|}|D]}| |i}q|sn|rt|t|j}||j|}|jt|dd|d| d}q||S)z Gets a list of available versions for a collection on a Galaxy server. :param namespace: The collection namespace. :param name: The collection name. :return: A list of versions that are available. FrrrTr8limitr'r?rTz/?%s=%dr_r5Nz%s.%szGError when getting available collection versions for %s.%s from %s (%s))r3r4rrPrcSg|]}|dqSr:r#)r~vr#r#r$ {z5GalaxyAPI.get_collection_versions..rcrd)rrEr?COLLECTION_PAGE_SIZEr rhrrr]rerr)r*rFrr@rAr rr)rNrr@ relative_linkr`pagination_pathpage_size_name versions_urlversions_url_inforrmodified_cache modified_daterQcached_modified_dater3rP results_keyrTrrhr#r#r$get_collection_versions9sv       z!GalaxyAPI.get_collection_versionsc Cs|jd|jd}|j|d||d|dg}t|}d||||j|jf}|j||dd}|d d |d p:gD} | sQtd |jd |d|d|| S)aG Gets the collection signatures from the Galaxy server about a specific Collection version. :param namespace: The collection namespace. :param name: The collection name. :param version: Version of the collection to get the information for. :return: A list of signature strings. rr8r?rTr|rfTrgcSrp) signaturer#)r~signature_infor#r#r$rrrsz7GalaxyAPI.get_collection_signatures..rzServer z has not signed r:) rrFr?rEr@rArr=r>rkr#r#r$get_collection_signaturess $z#GalaxyAPI.get_collection_signatures)NNNFNFN)NF)NN)NNN)T)r)%rLrrrfloatrrrrrpropertyrWrrrr0rArr&rrr rrr r"r,r0r2r6r8rIr[rernr~rr#r#r#r$rsv $     Z               -  A     Wr)G __future__rr?r functoolsrCrqrgrlrArS threadinghttpr http.clientrr urllib.errorrr urllib.parserrr r r r ansibler ransible.errorsransible.galaxy.user_agentransible.module_utils.apirransible.module_utils.sixr+ansible.module_utils.common.text.convertersrrransible.module_utils.urlsrransible.utils.displayransible.utils.hashingransible.utils.pathrr=LockrrtTOO_MANY_REQUESTS BAD_GATEWAYr+r&r0rWr]r{rEr) namedtuplerrtotal_orderingrr#r#r#r$sZ           M "*