def engine_max_version(): if 'DOCKER_VERSION' not in os.environ: return V2_1 version = os.environ['DOCKER_VERSION'].partition('-')[0] if version_lt(version, '1.10'): return V1 elif version_lt(version, '1.12'): return V2_0 return V2_1
def engine_max_version(): if 'DOCKER_VERSION' not in os.environ: return V3_5 version = os.environ['DOCKER_VERSION'].partition('-')[0] if version_lt(version, '1.10'): return V1 if version_lt(version, '1.12'): return V2_0 if version_lt(version, '1.13'): return V2_1 if version_lt(version, '17.06'): return V3_2 return V3_5
def engine_max_version(): if 'DOCKER_VERSION' not in os.environ: return V3_3 version = os.environ['DOCKER_VERSION'].partition('-')[0] if version_lt(version, '1.10'): return V1 if version_lt(version, '1.12'): return V2_0 if version_lt(version, '1.13'): return V2_1 if version_lt(version, '17.06'): return V3_2 return V3_3
def require_engine_version(self, minimum): # Drop '-dev' or '-rcN' suffix engine = self.client.version()['Version'].split('-', 1)[0] if version_lt(engine, minimum): skip( "Engine version is too low ({} < {})" .format(engine, minimum) )
def _labels(self): if version_lt(self.client._version, '1.23'): return None labels = self.labels.copy() if self.labels else {} labels.update({ LABEL_PROJECT: self.project, LABEL_VOLUME: self.name, }) return labels
def events(self, service_names=None): if version_lt(self.client.api_version, '1.22'): # New, better event API was introduced in 1.22. return self._legacy_event_processor(service_names) def build_container_event(event): container_attrs = event['Actor']['Attributes'] time = datetime.datetime.fromtimestamp(event['time']) time = time.replace( microsecond=microseconds_from_time_nano(event['timeNano'])) container = None try: container = Container.from_id(self.client, event['id']) except APIError: # Container may have been removed (e.g. if this is a destroy event) pass return { 'time': time, 'type': 'container', 'action': event['status'], 'id': event['Actor']['ID'], 'service': container_attrs.get(LABEL_SERVICE), 'attributes': dict([(k, v) for k, v in container_attrs.items() if not k.startswith('com.docker.compose.')]), 'container': container, } def yield_loop(service_names): for event in self.client.events(filters={'label': self.labels()}, decode=True): # TODO: support other event types if event.get('Type') != 'container': continue try: if event['Actor']['Attributes'][ LABEL_SERVICE] not in service_names: continue except KeyError: continue yield build_container_event(event) return yield_loop( set(service_names) if service_names else self.service_names)
def events(self, service_names=None): if version_lt(self.client.api_version, '1.22'): # New, better event API was introduced in 1.22. return self._legacy_event_processor(service_names) def build_container_event(event): container_attrs = event['Actor']['Attributes'] time = datetime.datetime.fromtimestamp(event['time']) time = time.replace( microsecond=microseconds_from_time_nano(event['timeNano']) ) container = None try: container = Container.from_id(self.client, event['id']) except APIError: # Container may have been removed (e.g. if this is a destroy event) pass return { 'time': time, 'type': 'container', 'action': event['status'], 'id': event['Actor']['ID'], 'service': container_attrs.get(LABEL_SERVICE), 'attributes': dict([ (k, v) for k, v in container_attrs.items() if not k.startswith('com.docker.compose.') ]), 'container': container, } def yield_loop(service_names): for event in self.client.events( filters={'label': self.labels()}, decode=True ): # TODO: support other event types if event.get('Type') != 'container': continue try: if event['Actor']['Attributes'][LABEL_SERVICE] not in service_names: continue except KeyError: continue yield build_container_event(event) return yield_loop(set(service_names) if service_names else self.service_names)
def process_service(self, service, silent=False): if 'image' not in service.options: # [Developer] I know its peretty bad hack, I can improve on this by having a clone of this object image_with_tag = self.get_repository_name_with_tag(service) log.info('Service (%s) docker image should be (%s)' % (service.name, image_with_tag)) service.options['image'] = image_with_tag repo, tag, _ = parse_repository_tag(service.options['image']) kwargs = { 'tag': tag or 'latest', 'stream': True, 'platform': getattr(service, 'platform', None), } if kwargs['platform'] and version_lt(service.client.api_version, '1.35'): raise OperationFailedError( 'Impossible to perform platform-targeted pulls for API version < 1.35' ) self.try_to_pull_otherwise_build(service, repo, kwargs)
def require_api_version(self, minimum): api_version = self.client.version()['ApiVersion'] if version_lt(api_version, minimum): pytest.skip("API version is too low ({} < {})".format( api_version, minimum))
def require_api_version(self, minimum): api_version = self.client.version()['ApiVersion'] if version_lt(api_version, minimum): skip("API version is too low ({} < {})".format(api_version, minimum))
def engine_version_too_low_for_v2(): if 'DOCKER_VERSION' not in os.environ: return False version = os.environ['DOCKER_VERSION'].partition('-')[0] return version_lt(version, '1.10')
def _get_container_create_options(self, override_options, number, one_off=False, previous_container=None): add_config_hash = (not one_off and not override_options) container_options = dict((k, self.options[k]) for k in DOCKER_CONFIG_KEYS if k in self.options) override_volumes = override_options.pop('volumes', []) container_options.update(override_options) if not container_options.get('name'): container_options['name'] = self.get_container_name( number, one_off) container_options.setdefault('detach', True) # If a qualified hostname was given, split it into an # unqualified hostname and a domainname unless domainname # was also given explicitly. This matches behavior # until Docker Engine 1.11.0 - Docker API 1.23. if (version_lt(self.client.api_version, '1.23') and 'hostname' in container_options and 'domainname' not in container_options and '.' in container_options['hostname']): parts = container_options['hostname'].partition('.') container_options['hostname'] = parts[0] container_options['domainname'] = parts[2] if (version_gte(self.client.api_version, '1.25') and 'stop_grace_period' in self.options): container_options['stop_timeout'] = self.stop_timeout(None) if 'ports' in container_options or 'expose' in self.options: container_options['ports'] = build_container_ports( formatted_ports(container_options.get('ports', [])), self.options) if 'volumes' in container_options or override_volumes: container_options['volumes'] = list( set(container_options.get('volumes', []) + override_volumes)) container_options['environment'] = merge_environment( self.options.get('environment'), override_options.get('environment')) binds, affinity = merge_volume_bindings( container_options.get('volumes') or [], self.options.get('tmpfs') or [], previous_container) override_options['binds'] = binds container_options['environment'].update(affinity) container_options['volumes'] = dict( (v.internal, {}) for v in container_options.get('volumes') or {}) secret_volumes = self.get_secret_volumes() if secret_volumes: override_options['binds'].extend(v.repr() for v in secret_volumes) container_options['volumes'].update( (v.internal, {}) for v in secret_volumes) container_options['image'] = self.image_name container_options['labels'] = build_container_labels( container_options.get('labels', {}), self.labels(one_off=one_off), number, self.config_hash if add_config_hash else None) # Delete options which are only used in HostConfig for key in HOST_CONFIG_KEYS: container_options.pop(key, None) container_options['host_config'] = self._get_container_host_config( override_options, one_off=one_off) networking_config = self.build_default_networking_config() if networking_config: container_options['networking_config'] = networking_config container_options['environment'] = format_environment( container_options['environment']) return container_options
def wrapped(self, *args, **kwargs): if until and not version_lt(self.client._version, until): return f(self, *args, **kwargs) if not self.client.info()['ExperimentalBuild']: pytest.skip('Feature requires Docker Engine experimental mode') return f(self, *args, **kwargs)