def __monitor_vm_events(self): session = self.get_session() vmuuid = self.get_uuid() ssh_client = ssh_helper.prepare_ssh_client(session, vmuuid) try: cmd = docker.prepare_request_cmd() log.info("__monitor_vm_events is running '%s' on VM '%s'" % (cmd, vmuuid)) stdin, stdout, _ = ssh_client.exec_command(cmd) stdin.write(docker.prepare_request_stdin('GET', '/events')) self._ssh_client = ssh_client # Not that we are listening for events, get the latest state docker.update_docker_ps(self) # set unblocking io for select.select stdout_fd = stdout.channel.fileno() fcntl.fcntl(stdout_fd, fcntl.F_SETFL, os.O_NONBLOCK | fcntl.fcntl(stdout_fd, fcntl.F_GETFL)) # @todo: should make this more sane skippedheader = False openbrackets = 0 data = "" while not self._stop_monitoring_request: rlist, _, _ = select.select([stdout_fd], [], [], MONITOR_EVENTS_POLL_INTERVAL) if not rlist: continue try: # @todo: should read more than one char at once lastread = stdout.read(1) except IOError, exception: if exception[0] not in (errno.EAGAIN, errno.EINTR): raise sys.exc_clear() continue if lastread == '': break data = data + lastread if (not skippedheader and lastread == "\n" and len(data) >= 4 and data[-4:] == "\r\n\r\n"): data = "" skippedheader = True elif lastread == '{': openbrackets = openbrackets + 1 elif lastread == '}': openbrackets = openbrackets - 1 if openbrackets == 0: event = simplejson.loads(data) self.handle_docker_event(event) data = "" if len(data) >= 2048: raise util.XSContainerException('__monitor_vm_events' + 'is full') finally: try: ssh_client.close() except Exception: util.log.exception("Error when closing ssh_client for %r" % ssh_client) log.info('__monitor_vm_events (%s) exited' % cmd)
def execute_docker_event_listen(session, vmuuid, stoprequest): skippedheader = False data = "" openbrackets = 0 request = "GET /events HTTP/1.0\r\n\r\n" connector = _get_connector(session, vmuuid) for read_data in connector.execute_docker_data_listen(session, vmuuid, request, stoprequest): for character in read_data: data = data + character if (not skippedheader and character == "\n" and len(data) >= 4 and data[-4:] == "\r\n\r\n"): data = "" skippedheader = True elif character == '{': openbrackets = openbrackets + 1 elif character == '}': openbrackets = openbrackets - 1 if openbrackets == 0: event = util.convert_dict_to_ascii(json.loads(data)) yield event data = "" if len(read_data) >= 2048: raise util.XSContainerException('execute_docker_event_listen' + 'is full')
def get_top_dict(session, vmuuid, container): _verify_or_throw_container(container) result = _get_api_json(session, vmuuid, '/containers/%s/top' % (container)) titles = result['Titles'] psentries = [] for process in result['Processes']: process_dict = {} item = 0 if len(titles) > len(process): raise util.XSContainerException("Can't parse top output") for title in titles: process_dict.update({title: process[item]}) item = item + 1 psentries.append({'Process': process_dict}) return psentries
def find_latest_tools_iso_path(): tools_iso_paths = glob.glob(XS_TOOLS_ISO_PATH) if len(tools_iso_paths) == 0: raise util.XSContainerException("Can't locate XS tools in %s." % (XS_TOOLS_ISO_PATH)) elif len(tools_iso_paths) == 1: return tools_iso_paths[0] else: # Let's first loose the xs-tools.iso without a release tools_iso_path_wo_releaseless = [] for path in tools_iso_paths: basename = os.path.basename(path) if basename.count("-") != 2: tools_iso_path_wo_releaseless.append(path) # Then sort the remaining tools_iso_path_wo_releaseless.sort( key=lambda s: map(str, re.split('[.-]', s))) # And return the last number out of the sorted list return tools_iso_path_wo_releaseless[-1]
def get_suitable_vm_ip(session, vmuuid): ips = get_vm_ips(session, vmuuid) stage1filteredips = [] for address in ips.itervalues(): if ':' not in address: # If we get here - it's ipv4 if address.startswith('169.254.'): # we prefer host internal networks and put them at the front stage1filteredips.insert(0, address) else: stage1filteredips.append(address) else: # Ignore ipv6 as Dom0 won't be able to use it pass for address in stage1filteredips: if util.test_connection(address, 22): return address raise util.XSContainerException( "No valid IP found for vmuuid %s" % (vmuuid))
def _interact_with_api(session, vmuuid, request_type, request, message_error=False): provided_stdin = prepare_request_stdin(request_type, request) stdout = ssh_helper.execute_ssh(session, vmuuid, prepare_request_cmd(), stdin_input=provided_stdin) headerend = stdout.index('\r\n\r\n') header = stdout[:headerend] body = stdout[headerend + 4:] # ToDo: Should use re headersplits = header.split('\r\n', 2)[0].split(' ') # protocol = headersplits[0] statuscode = headersplits[1] if statuscode[0] != '2': # this did not work status = ' '.join(headersplits[2:]) failure_title = "Container Management Error" failure_body = body.strip() if failure_body == "": if statuscode == "304": # 304 does not have a body and is quite common. failure_body = ("The requested operation is currently not " "possible. Please try again later.") else: failure_body = ("The requested operation failed.") failure_body = failure_body + " (" + statuscode + ")" if ":" in failure_body: (failure_title, failure_body) = failure_body.split(":", 1) if message_error: api_helper.send_message(session, vmuuid, failure_title, failure_body) message = ("Request '%s' led to status %s - %s: %s" % (request, status, failure_title, failure_body)) log.info(message) raise util.XSContainerException(message) return body
def _verify_or_throw_container(container): if not re.match('^[a-z0-9_.-]+$', container): raise util.XSContainerException("Invalid container")