def _watch_resource_completions(self, timeout): ''' Watch and wait for resource completions. Returns lists of resources in various conditions for the calling function to handle. ''' LOG.debug( 'Starting to wait on: namespace=%s, resource type=%s, ' 'label_selector=(%s), timeout=%s', self.chart_wait.release_id.namespace, self.resource_type, self.label_selector, timeout) ready = {} modified = set() found_resources = False kwargs = { 'namespace': self.chart_wait.release_id.namespace, 'label_selector': self.label_selector, 'timeout_seconds': timeout } resource_list = self.get_resources(**kwargs) for resource in resource_list.items: # Only include resources that should be included in wait ops if self.include_resource(resource): ready[resource.metadata.name] = self.handle_resource(resource) if not resource_list.items: if not self.required: msg = 'Skipping non-required wait, no %s resources found.' LOG.debug(msg, self.resource_type) return (False, modified, [], found_resources) else: found_resources = True if all(ready.values()): return (False, modified, [], found_resources) # Only watch new events. kwargs['resource_version'] = resource_list.metadata.resource_version w = watch.Watch() for event in w.stream(self.get_resources, **kwargs): event_type = event['type'].upper() resource = event['object'] resource_name = resource.metadata.name resource_version = resource.metadata.resource_version # Skip resources that should be excluded from wait operations if not self.include_resource(resource): continue msg = ( 'Watch event: type=%s, name=%s, namespace=%s, ' 'resource_version=%s') LOG.debug( msg, event_type, resource_name, self.chart_wait.release_id.namespace, resource_version) if event_type in {'ADDED', 'MODIFIED'}: found_resources = True resource_ready = self.handle_resource(resource) ready[resource_name] = resource_ready if event_type == 'MODIFIED': modified.add(resource_name) elif event_type == 'DELETED': LOG.debug('Resource %s: removed from tracking', resource_name) ready.pop(resource_name) elif event_type == 'ERROR': LOG.error( 'Resource %s: Got error event %s', resource_name, event['object'].to_dict()) raise k8s_exceptions.KubernetesErrorEventException( 'Got error event for resource: %s' % event['object']) else: LOG.error( 'Unrecognized event type (%s) for resource: %s', event_type, event['object']) raise ( k8s_exceptions. KubernetesUnknownStreamingEventTypeException( 'Got unknown event type (%s) for resource: %s' % (event_type, event['object']))) if all(ready.values()): return (False, modified, [], found_resources) return ( True, modified, [name for name, is_ready in ready.items() if not is_ready], found_resources)
def _watch_pod_completions(self, namespace, label_selector, timeout=100): ''' Watch and wait for pod completions. Returns lists of pods in various conditions for the calling function to handle. ''' LOG.debug( 'Starting to wait on pods: namespace=%s, label_selector=(%s), ' 'timeout=%s', namespace, label_selector, timeout) ready_pods = {} modified_pods = set() w = watch.Watch() first_event = True found_events = False # Watch across specific namespace, or all kwargs = { 'label_selector': label_selector, 'timeout_seconds': timeout, } if namespace: func_to_call = self.client.list_namespaced_pod kwargs['namespace'] = namespace else: func_to_call = self.client.list_pod_for_all_namespaces for event in w.stream(func_to_call, **kwargs): if first_event: pod_list = func_to_call(**kwargs) for pod in pod_list.items: LOG.debug('Setting up to wait for pod %s namespace=%s', pod.metadata.name, pod.metadata.namespace) ready_pods[pod.metadata.name] = False first_event = False event_type = event['type'].upper() pod_name = event['object'].metadata.name LOG.debug('Watch event for pod %s namespace=%s label_selector=%s', pod_name, namespace, label_selector) if event_type in {'ADDED', 'MODIFIED'}: found_events = True status = event['object'].status pod_phase = status.phase pod_ready = True if (pod_phase == 'Succeeded' or (pod_phase == 'Running' and self._get_pod_condition( status.conditions, 'Ready') == 'True')): LOG.debug('Pod %s is ready!', pod_name) else: pod_ready = False LOG.debug( 'Pod %s not ready: conditions:\n%s\n' 'container_statuses:\n%s', pod_name, status.conditions, status.container_statuses) ready_pods[pod_name] = pod_ready if event_type == 'MODIFIED': modified_pods.add(pod_name) elif event_type == 'DELETED': LOG.debug('Pod %s: removed from tracking', pod_name) ready_pods.pop(pod_name) elif event_type == 'ERROR': LOG.error('Pod %s: Got error event %s', pod_name, event['object'].to_dict()) raise exceptions.KubernetesErrorEventException( 'Got error event for pod: %s' % event['object']) else: LOG.error('Unrecognized event type (%s) for pod: %s', event_type, event['object']) raise exceptions.KubernetesUnknownStreamingEventTypeException( 'Got unknown event type (%s) for pod: %s' % (event_type, event['object'])) if all(ready_pods.values()): return (False, modified_pods, [], found_events) # NOTE(mark-burnett): This path is reachable if there are no pods # (unlikely) or in the case of the watch timing out. return (not all(ready_pods.values()), modified_pods, [name for name, ready in ready_pods.items() if not ready], found_events)
def wait_one_time(self, label_selector='', timeout=100): LOG.debug('Starting to wait: label_selector=%s, timeout=%s', label_selector, timeout) ready_pods = {} modified_pods = set() w = watch.Watch() first_event = True for event in w.stream(self.client.list_pod_for_all_namespaces, label_selector=label_selector, timeout_seconds=timeout): if first_event: pod_list = self.client.list_pod_for_all_namespaces( label_selector=label_selector, timeout_seconds=timeout) for pod in pod_list.items: LOG.debug('Setting up to wait for pod %s', pod.metadata.name) ready_pods[pod.metadata.name] = False first_event = False event_type = event['type'].upper() pod_name = event['object'].metadata.name if event_type in {'ADDED', 'MODIFIED'}: status = event['object'].status is_ready = status.phase in READY_PHASES if is_ready: LOG.debug('Pod %s (%s) is_ready=%s', pod_name, event_type, is_ready) else: container_statuses = status.container_statuses conditions = status.conditions LOG.debug( 'Pod %s (%s) is_ready=%s container_statuses=%s ' 'conditions=%s', pod_name, event_type, is_ready, container_statuses, conditions) ready_pods[pod_name] = is_ready if event_type == 'MODIFIED': modified_pods.add(pod_name) elif event_type == 'DELETED': LOG.debug('Removing pod %s from tracking', pod_name) ready_pods.pop(pod_name) elif event_type == 'ERROR': LOG.error('Got error event for pod: %s', event['object'].to_dict()) raise exceptions.KubernetesErrorEventException( 'Got error event for pod: %s' % event['object']) else: LOG.error('Unrecognized event type (%s) for pod: %s', event_type, event['object']) raise exceptions.KubernetesUnknownStreamingEventTypeException( 'Got unknown event type (%s) for pod: %s' % (event_type, event['object'])) if all(ready_pods.values()): return (False, modified_pods, []) # NOTE(mark-burnett): This path is reachable if there are no pods # (unlikely) or in the case of the watch timing out. return (not all(ready_pods.values()), modified_pods, [name for name, ready in ready_pods.items() if not ready])