a )g@sddlmZmZmZeZddlZddlZddlZddl Z ddl Z ddl Z ddl Z ddl Z ddlZddlZddlZddlmZddlmZmZddlmZmZddlmZmZmZmZmZddl m!Z"ddl#m$Z$dd l%m&Z&dd l'm(Z(dd l'm)Z)dd l*m+Z+dd l,m-Z-m.Z.m/Z/ddl0m1Z1m2Z2ddl3m4Z4ddl5m6Z6ddl7m8Z8e4Z9e:Z;dZhZ?ddZ@ddZAddZBddZCe@ddZDddZEGd d!d!e$ZFeGd"gd#ZHGd$d%d%ZIejJGd&d'd'ZKdS)()absolute_importdivisionprint_functionN) 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_safedicsfdd}|S)Ncs6t|i|WdS1s(0YdSN) _CACHE_LOCK)argskwargsfunc6/usr/lib/python3.9/site-packages/ansible/galaxy/api.pywrapped0szcache_lock..wrappedr$)r#r&r$r"r% cache_lock/s r'cCs^t|tr|jtvrdSt|trZt|dd}rZt|trB|j}t|tt t t j frZdSdS)NTorig_excF) isinstance GalaxyError http_codeRETRY_HTTP_ERROR_CODESrgetattrr reason TimeoutErrorrrsockettimeout) exceptionr(r$r$r%should_retry_error7s r3csfdd}|S)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|jsjtd|j|j}d|j|f}|jdks@|jdkrDd}z|j|d|dd}Wntttt fy}zx| d s| d rt |d }z|j|d|dd}Wn4ty}z|j d kr|WYd}~n d}~00WYd}~n d}~00d |vrtd ||jf||_| d ddi}t|dgkrBd|d<||_tdd||j|jft|j}t|} | stdjdd||j|jf|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 %s)_available_api_versionsdisplayvvvv api_servername _call_galaxyrr* ValueErrorKeyErrorendswith_urljoinr+getlistkeysjoinset intersection__name__) selfr r!n_urlr6dataerrZnew_errr9Zcommon_versions)r5versionsr$r%r&SsN  . z-g_connect..decorator..wrappedr$)r5r&rR)r5r% decoratorRs8zg_connect..decoratorr$)rRrTr$rSr% g_connectKs :rUcCs<t|}d}z |j}Wnty(Yn0d|j|p6dfS)z* Gets the cache ID for the URL specified. Nz%s:%s)r portrChostname)urlurl_inforWr$r$r% get_cache_ids  r[cCshd}tj|sXtdt|t|dt|dWdn1sN0Yt|j }|tj @rt dt|dSt|dd }t| d d }Wdn1s0Yzt |}Wntyd}Yn0t|tr|d d|krdtd t|d |i}t|d d(}|tt |d d Wdn1sZ0Y|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_stricterrorsversionz:Galaxy cache file at '%s' has an invalid version, clearingwb)ospathisfiler>r?ropenchmodstatst_modeS_IWOTHwarningreadjsonloadsrCr)dictrGwriterdumps)Z b_cache_pathZ cache_versionZ cache_modefdZjson_valr7r$r$r% _load_caches.  *  .  8rvcGsddd|dDS)N/css$|]}|rt|dddVqdS)rarbrwN)rstrip).0ar$r$r% z_urljoin..)rV)rJ)r r$r$r%rFsrFcs eZdZdZfddZZS)r*z( Error for bad Galaxy server responses. c sJtt|||j|_||_zt|}t |}Wnt t fyVi}Yn0|j d}d|vr|d|j}|dd}d||j||f}nd|vr|dg} | sig} g} | D]F} | d p| d p|j} | dpd} d |j| | f}| |qd |d | f}n|d|j}d||j|f}t||_dS)Nrwr;messagecodeZUnknownz(%s (HTTP Code: %d, Message: %s Code: %s)v3rcZdetailtitlez%(HTTP Code: %d, Message: %s Code: %s)z%s %sr<defaultz%s (HTTP Code: %d, Message: %s))superr*__init__r~r+geturlrYrrorprqAttributeErrorrCsplitrGr.appendrJrr})rNZ http_errorr}Zhttp_msgZerr_infoZ url_splitZ galaxy_msgr~Zfull_error_msgrcZ message_lineserrorZ error_msgZ error_codeZ message_line __class__r$r%rs6        zGalaxyError.__init__)rM __module__ __qualname____doc__r __classcell__r$r$rr%r*sr*CollectionMetadata) namespacerA 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)rrArd download_urlartifact_sha256 dependenciessignatures_url signatures) rNrrArdrrrrrr$r$r%rsz"CollectionVersionMetadata.__init__N)rMrrrr$r$r$r%rsrc @seZdZdZdddddddeddf ddZd d Zd d Zd dZddZ e e gdddZ e eddddeddEddZdFddZeddZe 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||_||_||_||_||_||_||_| |_|p6i|_| |_ | |_ t t j dd} t| ddtj| d|_| rt>tj|jrtdt|jt|jWdn1s0Yd|_| st|j|_td|j|jfdS)Nrarbir_sapi.jsonzClearing cache file (%s)z$Validate TLS certificates for %s: %s)galaxyrAusernamepasswordtokenr@validate_certsr1r= _priority_server_timeoutrCZGALAXY_CACHE_DIRrrfrgrJ _b_cache_pathrexistsr>r?rremove_cachervdebug)rNrrArYrrrravailable_api_versionsZclear_response_cacheZno_cachepriorityr1Z b_cache_dirr$r$r%rs.  * zGalaxyAPI.__init__cCs t|jS)z3Render GalaxyAPI as a native string representation.)rrArNr$r$r%__str__3szGalaxyAPI.__str__cCs t|jS)z9Render GalaxyAPI as a unicode/text string representation.)rrArr$r$r% __unicode__8szGalaxyAPI.__unicode__cCsdj||j|j|jdS)z9Render GalaxyAPI as an inspectable string representation.z><{instance!s} "{name!s}" @ {url!s} with priority {priority!s}>)instancerArrY)formatrArr@rr$r$r%__repr__=s zGalaxyAPI.__repr__cCs(t||jstS|j|jkp&|j|jkS)z:Return whether the instance priority is higher than other.)r)rNotImplementedrrA)rNZother_galaxy_apir$r$r%__lt__Hs    zGalaxyAPI.__lt__)r:r;rcCs|jSr)r=rr$r$r%rSsz GalaxyAPI.available_api_versions()ZretriesZ delay_baseZdelay_threshold)Zbackoff_iteratorr3c  Cst|} t|} |s| j}t| j} |r"|jr"|j| i} d} d}|| vrttj| |d| }tj |k}d| vpd| v}|r|s| |}| drd|vrdd dii}nd di}g|d <|d D]}|d  |qn|d }|S|s"tj }|tj d d 7}| | dd | |<|p*i}|j|||dz4td|tt|||j|||jtdd}Wnlty}zt||WYd}~nFd}~0ty}z$td|t|f|dWYd}~n d}~00t|dd}zt|}Wn*ty&td|jt|fYn0|r|jr|j| |}d}dD]}||vrL|}qhqL|rd|d<|d g}||D]}| |qn||d <|S)Nz%Y-%m-%dT%H:%M:%SZFexpiresZpageoffset paginatedz/v3/linksnextresultsr\)Zdays)rr)requiredzCalling Galaxy at %ssafe)rPrheadersr5r1 http_agentZfollow_redirectsz8Unknown error when attempting to call Galaxy at '%s': %sr(rarbz5Failed to parse Galaxy response from '%s' as JSON: %s)rPrT) r r[rgr queryr setdefaultdatetimestrptimeZutcnowrGrZ timedeltastrftime_add_auth_tokenr>r?rrrrrrr* ExceptionrrrorprqrCrY)rNrYr rr5 auth_requiredr6r7 cache_keyrZZcache_idr server_cacheZiso_datetime_formatZvalidrZis_paginated_urlZ path_cacheresresultrespeZ resp_datarPZ paginated_keykeyrr$r$r%rBYs            zGalaxyAPI._call_galaxycCsDd|vr dS|js*|r*tdttj|jr@||jdS)NZ AuthorizationzMNo access token or username set. A token can be set with --api-key or at {0}.)rrrrrZGALAXY_TOKEN_PATHupdater)rNrrY token_typerr$r$r%rs zGalaxyAPI._add_auth_tokencCsLt|jdd*}|tt|jddWdn1s>0YdS)Nrer_rarb)rirrsrrprtr)rNrur$r$r% _set_cacheszGalaxyAPI._set_cacher:c Cst|j|jddd}td|i}zt|||jdt|jd}Wndtyp}zt |dWYd}~n@d}~0t y}z t d t ||d WYd}~n d}~00t t|d d }|S) z2 Retrieve an authentication token r:tokensrw github_tokenPOST)rPrr5rr1z$Attempting to authenticate to galaxyNz$Unable to authenticate to galaxy: %srrarb)rFr@rr rrrrrr*rrrrprqrro)rNrrYr rrrPr$r$r% authenticates *zGalaxyAPI.authenticatecCst|j|jddd}|||r$|ndd}|r:||d<n"|dr\|tddd |d<|j|t|d d }|d d r|d S|S) z( Post an import request r:importsrwrV) github_user github_repoZgithub_referenceZalternate_role_namez ansible-roler\Nrr r5r)rFr@r startswithlenrBr rG)rNrrZ reference role_namerYr rPr$r$r%create_import_tasks    zGalaxyAPI.create_import_taskcCsdt|j|jdd}|dur*d||f}n(|durJ|durJd|||f}ntd||}|dS)z5 Check the status of an import task. r:rNz%s?id=%dz %s?github_user=%s&github_repo=%sz/Expected task_id or github_user and github_repor)rFr@rrrB)rNtask_idrrrYrPr$r$r%get_import_tasks zGalaxyAPI.get_import_taskcCsttt|}z>|d}d|dd}|d}|rLtd||fWntyltd|Yn0t|j |j ddd||f}| |}t |d dkr|d dSd S) z& Find a role by name. .rz$- downloading role '%s', owned by %szAInvalid role name (%s). Specify role as format: username.rolenamer:rolesz?owner__username=%s&name=%srN) rurlquoterrrJr>rrrFr@rrBr)rNrnotifypartsZ user_namerYrPr$r$r%lookup_role_by_names      zGalaxyAPI.lookup_role_by_namec Csg}zt|j|jdd||d}||}|d}|dddu}t|j}d|j|jf}|st||d}||}||d7}|dddu}q\Wn<ty} z$t d||t | fWYd} ~ n d} ~ 00|S) z Fetch the list of related items for the given role. The url comes from the 'related' field of the role. r:rz ?page_size=50r next_linkNz%s://%s/zSUnable to retrieve role (id=%s) data (%s), but this is not fatal so we continue: %s) rFr@rrBrGr schemenetlocrr>rnr) rNZrelatedZrole_idrrYrPdonerZZbase_urlrr$r$r%fetch_role_relateds(     zGalaxyAPI.fetch_role_relatedc Cszt|j|jd|d}||}d|vr4|d}n|}d}d|vrT|dddu}|st|j|d}||}||d7}|dddu}qT|WSty}z td|t|fWYd}~n d}~00dS) z4 Fetch the list of items specified. r:z ?page_sizerTrrNz"Failed to download the %s list: %s)rFr@rrBrGrrr)rNZwhatrYrPrrrr$r$r%get_list2s"    zGalaxyAPI.get_listc Kst|j|jdddd}|r4|dttt|7}|dd}|dd}|dd}|d d}|rt|tr| d }|d d |7}|rt|tr| d }|d d |7}|r|d|7}|r|d|7}| |}|S)Nr:searchr?z&autocomplete=tags platforms page_sizeauthor,z&tags_autocomplete=+z&platforms_autocomplete=z &page_size=%sz&username_autocomplete=%s) rFr@rrrrrGr)rrrJrB) rNrr!Z search_urlrrrrrPr$r$r% search_rolesJs&         zGalaxyAPI.search_rolescCs>t|j|jddd}t||||d}|j||dd}|S)Nr:notification_secretsrw)sourcerrsecretrr)rFr@rr rB)rNrrrrrYr rPr$r$r% add_secrethszGalaxyAPI.add_secretcCs&t|j|jdd}|j|dd}|S)Nr:rT)rrFr@rrB)rNrYrPr$r$r% list_secretstszGalaxyAPI.list_secretscCs.t|j|jdd|d}|j|ddd}|S)Nr:rrwTDELETErr5r)rNZ secret_idrYrPr$r$r% remove_secretzszGalaxyAPI.remove_secretcCs2t|j|jddd||f}|j|ddd}|S)Nr:Z removerolez?github_user=%s&github_repo=%sTrrr)rNrrrYrPr$r$r% delete_roles  zGalaxyAPI.delete_roler;rc Cs&td||j|jft|dd}tj|sBtdt|nt |s\tdt|t |d"}t | tjd}Wdn1s0Yt||d d d \}}|t|d }d |jvrt|j|jd ddd}nt|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 %srarbz2The 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^)Z hash_funcNzapplication/octet-stream)filenameZ mime_type)sha256file)z Content-typezContent-lengthrZ artifacts collectionsrwr;rTz+Error when publishing collection to %s (%s))r rr5rr6Ztask)r>rAr@rrfrgrrrtarfileZ is_tarfilerirrohashlibrrrrrFrB) rNZcollection_pathZb_collection_pathZcollection_tarrZ content_typeZ b_form_datarrOrr$r$r%publish_collections:    0   zGalaxyAPI.publish_collectionrc Cs d}d}d|jvr,t|j|jdd|d}nt|j|jdd|d}td|t}d }|d ksxt||kr2z|j|d d d |d}WnTty}z<|jdkrtd|t |WYd}~q^WYd}~n d}~00| dd}| ddrq2td||ft |t d|d}q^|dkrLt dt || dgD]h} | d} | dkrtd| dn8| dkrtd| dntd| | dfqX|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. ZwaitingNrzimports/collectionsrwr;zcollection-importsz1Waiting until Galaxy import task %s has completedrrr4Tz,Error when getting import task results at %s)r5rr6r8zJGalaxy import process has not started, wait %s seconds before trying againstateZ 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: %sr}rnz!Galaxy import warning message: %szGalaxy import message: %s - %sZfailedr~ZUNKNOWN descriptionz&Unknown error, see %s for more detailsz+Galaxy import process failed: %s (Code: %s))rrFr@r>timerBr*r+ZvvvsleeprGminrrlowerrrn) rNrr1rrPZfull_urlstartwaitrr}r r~r r$r$r%wait_import_tasks`      "    zGalaxyAPI.wait_import_taskc Csd|jvr|jd}ddg}n|jd}ddg}t|j|d||d}d |||j|jf}|j||d }i}|D]\}} || d ||<qnt||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)rZ created_at)rZ updated_atr;)rZcreated)rmodifiedrrwz=Error when getting the collection info for %s.%s from %s (%s))r6N)rrFr@rArBrGr) rNrrAapi_pathZ field_mapZinfo_urlr6rPmetadataZ 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 png} 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. rr;rrRrwHError when getting collection version metadata for %s.%s:%s from %s (%s)Tr6r7rrrAZ collectionrdrZartifactrrrZhref)rrGr@rFrArBrr rNrrArdrZ url_pathsZn_collection_urlr6rPrr$r$r%get_collection_version_metadatas z)GalaxyAPI.get_collection_version_metadatac Cs2d}d|jvr&|jd}ddg}d}n|jd}dg}d|jvrDdnd}t|j|d ||d d |tf}t|}|j} |jr*|jt|i} | d i} z| ||j } Wn4t y} z| j d krȂgWYd} ~ Sd} ~ 00| d||fd}|| kr*| | d||f<|j| vr"| | =|d|||j|jf}z|j||d| d}Wn8t y} z| j d krtgWYd} ~ Sd} ~ 00d|vrd}nd}g}|dd||D7}|}|D]}| |i}q|sq&n$|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. FrrrTr;limitrrrRz/?%s=%drr8Nz%s.%szGError when getting available collection versions for %s.%s from %s (%s))r6r7rrPrcSsg|] }|dqS)rdr$)ryvr$r$r% ur|z5GalaxyAPI.get_collection_versions..rarb)rrFr@COLLECTION_PAGE_SIZEr rgrrr[rrr*r+rGrrArBrreplacer)rNrrAZ relative_linkrZpagination_pathZpage_size_nameZ versions_urlZversions_url_inforrZmodified_cacheZ modified_daterQZcached_modified_dater6rPZ results_keyrRrrgr$r$r%get_collection_versions3sj           z!GalaxyAPI.get_collection_versionsc Cs|jd|jd}|j|d||d|dg}t|}d||||j|jf}|j||dd}|z |d } Wn:tyt d |jd |d |d |gYS0dd| DSdS)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. rr;rrRrwrTrrzServer z has not signed r:cSsg|] }|dqS)Z signaturer$)ryZsignature_infor$r$r%rr|z7GalaxyAPI.get_collection_signatures..N) rrGr@rFrArBrrDr>r?rr$r$r%get_collection_signaturess   $ z#GalaxyAPI.get_collection_signatures)NNNFNFN)NF)NN)NNN)T)r)%rMrrrfloatrrrrrpropertyrUrrrr3rBrr'rrrrrrrrrrrrrrrrr!r#r$r$r$r%r st $      Y               -  A     W r)LZ __future__rrrtypeZ __metaclass__rr functoolsrrprfr0rkrr  threadinghttprZ http.clientrrZ urllib.errorrr urllib.parser rr r r rZansiblerrZansible.errorsrZansible.galaxy.user_agentrZansible.module_utils.apirrZansible.module_utils.sixrZansible.module_utils._textrrrZansible.module_utils.urlsrrZansible.utils.displayrZansible.utils.hashingrZansible.utils.pathrr>LockrrZTOO_MANY_REQUESTSZ BAD_GATEWAYr,r'r3rUr[rvrFr* namedtuplerrtotal_orderingrr$r$r$r%s\          D "*