<s> """<STR_LIT>""" <EOL> from oslo_log import log as logging <EOL> from oslo_serialization import jsonutils <EOL> from oslo_utils import timeutils <EOL> import requests <EOL> import nova . conf <EOL> from nova import context <EOL> from nova . i18n import _LW <EOL> from nova import objects <EOL> from nova . scheduler import filters <EOL> LOG = logging . getLogger ( __name__ ) <EOL> CONF = nova . conf . CONF <EOL> class AttestationService ( object ) : <EOL> def __init__ ( self ) : <EOL> self . api_url = CONF . trusted_computing . attestation_api_url <EOL> self . host = CONF . trusted_computing . attestation_server <EOL> self . port = CONF . trusted_computing . attestation_port <EOL> self . auth_blob = CONF . trusted_computing . attestation_auth_blob <EOL> self . key_file = None <EOL> self . cert_file = None <EOL> self . ca_file = CONF . trusted_computing . attestation_server_ca_file <EOL> self . request_count = <NUM_LIT:100> <EOL> self . verify = ( not CONF . trusted_computing . attestation_insecure_ssl <EOL> and self . ca_file or True ) <EOL> self . cert = ( self . cert_file , self . key_file ) <EOL> def _do_request ( self , method , action_url , body , headers ) : <EOL> action_url = "<STR_LIT>" % ( self . host , self . port , <EOL> self . api_url , action_url ) <EOL> try : <EOL> res = requests . request ( method , action_url , data = body , <EOL> headers = headers , cert = self . cert , <EOL> verify = self . verify ) <EOL> status_code = res . status_code <EOL> if status_code in ( requests . codes . OK , <EOL> requests . codes . CREATED , <EOL> requests . codes . ACCEPTED , <EOL> requests . codes . NO_CONTENT ) : <EOL> try : <EOL> return requests . codes . OK , jsonutils . loads ( res . text ) <EOL> except ( TypeError , ValueError ) : <EOL> return requests . codes . OK , res . text <EOL> return status_code , None <EOL> except requests . exceptions . RequestException : <EOL> return IOError , None <EOL> def _request ( self , cmd , subcmd , hosts ) : <EOL> body = { } <EOL> body [ '<STR_LIT:count>' ] = len ( hosts ) <EOL> body [ '<STR_LIT>' ] = hosts <EOL> cooked = jsonutils . dumps ( body ) <EOL> headers = { } <EOL> headers [ '<STR_LIT>' ] = '<STR_LIT:application/json>' <EOL> headers [ '<STR_LIT>' ] = '<STR_LIT:application/json>' <EOL> if self . auth_blob : <EOL> headers [ '<STR_LIT>' ] = self . auth_blob <EOL> status , res = self . _do_request ( cmd , subcmd , cooked , headers ) <EOL> return status , res <EOL> def do_attestation ( self , hosts ) : <EOL> """<STR_LIT>""" <EOL> result = None <EOL> status , data = self . _request ( "<STR_LIT:POST>" , "<STR_LIT>" , hosts ) <EOL> if data is not None : <EOL> result = data . get ( '<STR_LIT>' ) <EOL> return result <EOL> class ComputeAttestationCache ( object ) : <EOL> """<STR_LIT>""" <EOL> def __init__ ( self ) : <EOL> self . attestservice = AttestationService ( ) <EOL> self . compute_nodes = { } <EOL> admin = context . get_admin_context ( ) <EOL> computes = objects . ComputeNodeList . get_all ( admin ) <EOL> for compute in computes : <EOL> host = compute . hypervisor_hostname <EOL> self . _init_cache_entry ( host ) <EOL> def _cache_valid ( self , host ) : <EOL> cachevalid = False <EOL> if host in self . compute_nodes : <EOL> node_stats = self . compute_nodes . get ( host ) <EOL> if not timeutils . is_older_than ( <EOL> node_stats [ '<STR_LIT>' ] , <EOL> CONF . trusted_computing . attestation_auth_timeout ) : <EOL> cachevalid = True <EOL> return cachevalid <EOL> def _init_cache_entry ( self , host ) : <EOL> self . compute_nodes [ host ] = { <EOL> '<STR_LIT>' : '<STR_LIT>' , <EOL> '<STR_LIT>' : timeutils . normalize_time ( <EOL> timeutils . parse_isotime ( "<STR_LIT>" ) ) } <EOL> def _invalidate_caches ( self ) : <EOL> for host in self . compute_nodes : <EOL> self . _init_cache_entry ( host ) <EOL> def _update_cache_entry ( self , state ) : <EOL> entry = { } <EOL> host = state [ '<STR_LIT>' ] <EOL> entry [ '<STR_LIT>' ] = state [ '<STR_LIT>' ] <EOL> try : <EOL> entry [ '<STR_LIT>' ] = timeutils . normalize_time ( <EOL> timeutils . parse_isotime ( state [ '<STR_LIT>' ] ) ) <EOL> except ValueError : <EOL> try : <EOL> vtime = timeutils . parse_strtime ( state [ '<STR_LIT>' ] , fmt = "<STR_LIT>" ) <EOL> entry [ '<STR_LIT>' ] = timeutils . normalize_time ( vtime ) <EOL> except ValueError : <EOL> entry [ '<STR_LIT>' ] = '<STR_LIT>' <EOL> entry [ '<STR_LIT>' ] = timeutils . utcnow ( ) <EOL> self . compute_nodes [ host ] = entry <EOL> def _update_cache ( self ) : <EOL> self . _invalidate_caches ( ) <EOL> states = self . attestservice . do_attestation ( <EOL> list ( self . compute_nodes . keys ( ) ) ) <EOL> if states is None : <EOL> return <EOL> for state in states : <EOL> self . _update_cache_entry ( state ) <EOL> def get_host_attestation ( self , host ) : <EOL> """<STR_LIT>""" <EOL> if host not in self . compute_nodes : <EOL> self . _init_cache_entry ( host ) <EOL> if not self . _cache_valid ( host ) : <EOL> self . _update_cache ( ) <EOL> level = self . compute_nodes . get ( host ) . get ( '<STR_LIT>' ) <EOL> return level <EOL> class ComputeAttestation ( object ) : <EOL> def __init__ ( self ) : <EOL> self . caches = ComputeAttestationCache ( ) <EOL> def is_trusted ( self , host , trust ) : <EOL> level = self . caches . get_host_attestation ( host ) <EOL> return trust == level <EOL> class TrustedFilter ( filters . BaseHostFilter ) : <EOL> """<STR_LIT>""" <EOL> def __init__ ( self ) : <EOL> self . compute_attestation = ComputeAttestation ( ) <EOL> LOG . warning ( _LW ( '<STR_LIT>' <EOL> '<STR_LIT>' <EOL> '<STR_LIT>' <EOL> '<STR_LIT>' <EOL> '<STR_LIT>' <EOL> '<STR_LIT>' ) ) <EOL> run_filter_once_per_request = True <EOL> def host_passes ( self , host_state , spec_obj ) : <EOL> instance_type = spec_obj . flavor <EOL> extra = ( instance_type . extra_specs <EOL> if '<STR_LIT>' in instance_type else { } ) <EOL> trust = extra . get ( '<STR_LIT>' ) <EOL> host = host_state . nodename <EOL> if trust : <EOL> return self . compute_attestation . is_trusted ( host , trust ) <EOL> return True </s>
