3 \mea;@sJddlZddlZddlZddlZddlZddlZddlZddlZddlZddl Z ddl m Z ddlm Z ddl m Z ddlmZmZddlmZejeZGdddeZGd d d ejd ZGd d d eZGdddeZGdddeZGdddeZe eeeeefZeZej deej deej deej dedS)N)datetime)Event)Union) url_helperutil) DictRegistryc@s eZdZdS)ReportExceptionN)__name__ __module__ __qualname__r r /usr/lib/python3.6/handlers.pyrsrc@s&eZdZdZejddZddZdS)ReportingHandlerzBase class for report handlers. Implement :meth:`~publish_event` for controlling what the handler does with an event. cCsdS)zPublish an event.Nr )selfeventr r r publish_event"szReportingHandler.publish_eventcCsdS)z0Ensure ReportingHandler has published all eventsNr )rr r r flush&szReportingHandler.flushN)r r r __doc__abcabstractmethodrrr r r r rsr) metaclasscs*eZdZdZdfdd ZddZZS) LogHandlerzBPublishes events to the cloud-init log at the ``DEBUG`` log level.DEBUGc sbtt|jt|trn>|}ytt|j}Wn&tk rVt j d|tj }YnX||_ dS)Nzinvalid level '%s', using WARN) superr__init__ isinstanceintgetattrloggingupper ExceptionLOGwarningZWARNlevel)rr#Z input_level) __class__r r r-s   zLogHandler.__init__cCs2tjdjdd|j|jg}|j|j|jdS)N. cloudinitZ reporting)r getLoggerjoin event_typenamelogr# as_string)rrZloggerr r r r:szLogHandler.publish_event)r)r r r rrr __classcell__r r )r$r r*s rc@seZdZdZddZdS) PrintHandlerzPrint the event as a string.cCst|jdS)N)printr,)rrr r r rDszPrintHandler.publish_eventN)r r r rrr r r r r.Asr.cs6eZdZd fdd ZddZddZdd ZZS) WebHookHandlerNc stt|jt||||gr:tj||||d}|j|_ntj|_||_||_||_ t j |_ t |_tj|_tj|jd|_d|j_|jjdS)N) consumer_key token_key token_secretconsumer_secret)targetT)rr0ranyrZOauthUrlHelperreadurlendpointtimeoutretriesrZfetch_ssl_details ssl_detailsrflush_requestedqueueQueue threadingThreadprocess_requestsZevent_processordaemonstart) rr8r1r2r3r4r9r:Z oauth_helper)r$r r rIs$    zWebHookHandler.__init__cCsd}x|jjrJ|dkrJtjdx"|jjsD|jj|jjq$Wd}|jjdd}zty2|j |d|d|d|d|dd d d}Wn<t k r}z tjd |d||d7}WYdd}~XnXWd|jjXqWdS) NrzNMultiple consecutive failures in WebHookHandler. Cancelling all queued events.T)blockF)datar9r:r;Z log_req_respz0Failed posting event: %s. This was caused by: %s) r<Zis_setr!r"r=emptyZ get_nowait task_donegetr7r )rZconsecutive_failedargser r r rAjs4  zWebHookHandler.process_requestscCs@|j}tjd|j||jj|jtj||j|j |j fdS)NzQueuing POST to %s, data: %s) Zas_dictr!debugr8r=putjsondumpsr9r:r;)rrZ event_datar r r rszWebHookHandler.publish_eventcCs,|jjtjd|jj|jjdS)Nz(WebHookHandler flushing remaining events)r<setr!rOr=r(clear)rr r r rs   zWebHookHandler.flush)NNNNNN)r r r rrArrr-r r )r$r r0Hs&r0cseZdZdZdZdZdZeeZdZdZ dZ dZ d+Z d Z d Ze d ffdd ZeddZddZddZddZddZddZddZddZeed d d!d"Zd#d$Zd%d&Zd'd(Zd)d*ZZS),HyperVKvpReportingHandlera, Reports events to a Hyper-V host using Key-Value-Pair exchange protocol and can be used to obtain high level diagnostic information from the host. To use this facility, the KVP user-space daemon (hv_kvp_daemon) has to be running. It reads the kvp_file when the host requests the guest to enumerate the KVP's. This reporter collates all events for a module (origin|name) in a single json string in the dictionary. For more information, see https://technet.microsoft.com/en-us/library/dn798287.aspx#Linux%20guests iiiZ CLOUD_INITmsgresultZmsg_i,:z/var/lib/hyperv/.kvp_pool_1FNcsrtt|j||_tj|j||_tj|_|j |_ dj |j |j |_ tj|jd|_d|j_|jjdS)Nz{0}|{1})r5T)rrUr_kvp_file_path_truncate_guest_pool_file _event_typesr=r>q_get_incarnation_noZincarnation_noformat EVENT_PREFIXevent_key_prefixr?r@_publish_event_routineZpublish_threadrBrC)rZ kvp_file_pathZ event_types)r$r r rs   z"HyperVKvpReportingHandler.__init__cCs|jr dStjttj}zby*tjj||krHt|dWdQRXWn2t t fk r|}zt j d|WYdd}~XnXWdd|_XdS)a Truncate the pool file if it has not been truncated since boot. This should be done exactly once for the file indicated by KVP_POOL_FILE_GUEST constant above. This method takes a filename so that we can use an arbitrary file during unit testing. Since KVP is a best-effort telemetry channel we only attempt to truncate the file once and only if the file has not been modified since boot. Additional truncation can lead to loss of existing KVPs. Nwz$failed to truncate kvp pool file, %sT) _already_truncated_pool_filetimefloatruptimeospathgetmtimeopenOSErrorIOErrorr!r")clsZkvp_fileZ boot_timerNr r r r[s  "z3HyperVKvpReportingHandler._truncate_guest_pool_filec CsBtj}yttjt|Stk r<tjd|dSXdS)z use the time passed as the incarnation number. the incarnation number is the number which are used to distinguish the old data stored in kvp and the new data. z"uptime '%s' not in correct format.rN)rrgrrerf ValueErrorr!r")rZ uptime_strr r r r^s  z-HyperVKvpReportingHandler._get_incarnation_noc cs~t|jdh}tj|tj|j||j|j}x.t||jkr`|j |}|V|j|j}q4Wtj|tj WdQRXdS)z-iterate the kvp file from the current offset.rbN) rkrZfcntlflockLOCK_EXseekreadHV_KVP_RECORD_SIZElen_decode_kvp_itemLOCK_UN)roffsetf record_dataZkvp_itemr r r _iterate_kvpss   z'HyperVKvpReportingHandler._iterate_kvpscCsdj|j|j|jtjS)z the event key format is: CLOUD_INIT|||| [|subevent_index] z{0}|{1}|{2}|{3})r_rar)r*uuidZuuid4)rrr r r _event_key sz$HyperVKvpReportingHandler._event_keycCs*tjd|j|jf|jd|jd}|S)Nz%ds%dszutf-8)structpackHV_KVP_EXCHANGE_MAX_KEY_SIZEHV_KVP_EXCHANGE_MAX_VALUE_SIZEencode)rkeyvaluerIr r r _encode_kvp_items z*HyperVKvpReportingHandler._encode_kvp_itemcCsdt|}||jkr$tdj||j|d|jjdjd}||j|jjdjd}||dS)Nz$record_data len not correct {0} {1}.rzutf-8)rr)rwrvrr_rdecodestrip)rr|Zrecord_data_lenkvr r r rx!s  z*HyperVKvpReportingHandler._decode_kvp_itemc CsXt|jdB}tj|tjx|D]}|j|q"W|jtj|tjWdQRXdS)NZab)rkrZrqrrrswriterry)rr|r{rIr r r _append_kvp_item8s  z*HyperVKvpReportingHandler._append_kvp_itemc Cs||j=tj|}|dt|d}d}g}d|jd}x|||j<d||j<tj||jd}|jt|d} |j|dj|j|d| d } d j||} |j |j | | |d7}|| d}t|dkr>Pq>W|S) NrFr"z":"") separatorsz"{key}":"{desc}")rZdescz{}|{}) MSG_KEYrQrRrw DESC_IDX_KEYJSON_SEPARATORSHV_KVP_AZURE_MAX_VALUE_SIZEreplacer_appendr) rr meta_data descriptionZ des_in_jsoniZ result_arrayZmessage_place_holderZdata_without_descZ room_for_descrZsubkeyr r r _break_down@s.       z%HyperVKvpReportingHandler._break_down)rrreturnc Csht||jkr |d|jd}|j||g}y|j|Wn&ttfk rbtjd||YnXdS)zJWrite KVP key-value. Values will be truncated as needed. rrFzfailed posting kvp=%s value=%sN)rwrrrrlrmr!r")rrrrIr r r write_key^sz#HyperVKvpReportingHandler.write_keycCs|j|}|j|jtj|jjdd}t||jrB|j ||j<|j ||j <t j ||jd}t||jkr||j|||j S|j||}|gSdS)z encode the event into kvp data bytes. if the event content reaches the maximum length of kvp value. then it would be cut to multiple slices. Z)r*typeZts)rN)rr*r)rZutcfromtimestampZ timestampZ isoformathasattr RESULT_KEYrWrrrQrRrrwrrr)rrrrrrIr r r _encode_eventms     z'HyperVKvpReportingHandler._encode_eventcCsxd}y|jjdd}|d7}g}xP|dk rr||j|7}y|jjdd}|d7}Wq$tjk rnd}Yq$Xq$WzFy|j|Wn2ttfk r}ztj d|WYdd}~XnXWdxt |D]}|jj qWXWqt k rdSXqWdS)NrT)rErFFz failed posting events to kvp, %s) r]rLrr=ZEmptyrrlrmr!r"rangerKEOFError)rZitems_from_queuerZ encoded_datarN_r r r rbs*  "z0HyperVKvpReportingHandler._publish_event_routinecCs$|j s|j|jkr |jj|dS)N)r\r)r]rP)rrr r r rsz'HyperVKvpReportingHandler.publish_eventcCstjd|jjdS)Nz0HyperVReportingHandler flushing remaining events)r!rOr]r()rr r r rs zHyperVKvpReportingHandler.flush)rXrY) r r r rrrrrvr`rrrrZKVP_POOL_FILE_GUESTrdr classmethodr[r^r}rrrxrrstrrrrbrrr-r r )r$r rUs4     rUr+r/ZwebhookZhyperv)!rrqrQrrhr=rr?rer~rrZtypingrr&rrZcloudinit.registryrr'r r!r rABCMetarrr.r0rUZ HandlerTypeZavailable_handlersZ register_itemr r r r sD     `