<commit_before># -*- coding: utf-8 -*-
from __future__ import unicode_literals

from dockermap.map.policy.utils import is_initial

from ...functional import resolve_value
from .base import AttachedPreparationMixin, ForwardActionGeneratorMixin, AbstractActionGenerator


class ContainerUpdateGenerator(AttachedPreparationMixin, ForwardActionGeneratorMixin, AbstractActionGenerator):
    def __init__(self, policy, *args, **kwargs):
        super(ContainerUpdateGenerator, self).__init__(policy, *args, **kwargs)
        self.remove_status = policy.remove_status
        self.pull_latest = policy.pull_latest
        self.update_persistent = policy.update_persistent
        self.base_image_ids = {
            client_name: policy.images[client_name].ensure_image(
                self.iname_tag(policy.base_image), pull_latest=self.pull_latest)
            for client_name in policy.clients.keys()
        }
        self.path_vfs = {}

    def _check_links(self, map_name, c_config, instance_links):
        def _extract_link_info(host_link):
            link_name, __, link_alias = host_link.partition(':')
            return link_name[1:], link_alias.rpartition('/')[2]

        linked_dict = dict(map(_extract_link_info, instance_links))
        for link in c_config.links:
            if link.alias != linked_dict.get(self._policy.cname(map_name, link.container)):
                return False
        return True

    def _check_volumes(self, c_map, c_config, config_name, instance_name, instance_volumes):
        def _validate_bind(b_config, b_instance):
            for shared_volume in b_config.binds:
                bind_alias = shared_volume.volume
                host_path = c_map.host.get(bind_alias, b_instance)
                bind_path = resolve_value(c_map.volumes[bind_alias])
                bind_vfs = instance_volumes.get(bind_path)
                if not (bind_vfs and host_path == bind_vfs):
                    return False
                self.path_vfs[config_name, instance_name, bind_path] = bind_vfs
            return True

        def _validate_attached(a_config):
            for attached in a_config.attaches:
                attached_path = resolve_value(c_map.volumes[attached])
                attached_vfs = instance_volumes.get(attached_path)
                if not (attached_vfs and self.path_vfs.get((attached, None, attached_path)) == attached_vfs):
                    return False
                self.path_vfs[config_name, instance_name, attached_path] = attached_vfs
            return True

        def _check_config_paths(cr_config, cr_instance):
            for share in cr_config.shares:
                cr_shared_path = resolve_value(share)
                self.path_vfs[config_name, instance_name, cr_shared_path] = instance_volumes.get(share)
            if not _validate_bind(cr_config, cr_instance):
                return False
            if not _validate_attached(cr_config):
                return False
            for used in cr_config.uses:
                used_volume = used.volume
                used_path = resolve_value(c_map.volumes.get(used_volume))
                if used_path:
                    if self.path_vfs.get((used_volume, None, used_path)) != instance_volumes.get(used_path):
                        return False
                    continue
                ref_c_name, ref_i_name = self._policy.resolve_cname(used_volume, False)
                ref_config = c_map.get_existing(ref_c_name)
                if ref_config:
                    for share in ref_config.shares:
                        ref_shared_path = resolve_value(share)
                        i_shared_path = instance_volumes.get(ref_shared_path)
                        if self.path_vfs.get((ref_c_name, ref_i_name, ref_shared_path)) != i_shared_path:
                            return False
                        self.path_vfs[(config_name, instance_name, ref_shared_path)] = i_shared_path
                    _validate_bind(ref_config, ref_i_name)
                    _validate_attached(ref_config)
                else:
                    raise ValueError("Volume alias or container reference could not be resolved: {0}".format(used))
            return True

        return _check_config_paths(c_config, instance_name)

    def iname_tag(self, image, container_map=None):
        i_name = '{0}:latest'.format(image) if ':' not in image else image
        if container_map:
            return self._policy.iname(container_map, i_name)
        return i_name

    def generate_item_actions(self, map_name, c_map, container_name, c_config, instances, flags, *args, **kwargs):
        a_paths = {alias: resolve_value(c_map.volumes[alias]) for alias in c_config.attaches}
        for client_name, client, client_config in self._policy.get_clients(c_config, c_map):
            images = self._policy.images[client_name]
            existing_containers = self._policy.container_names[client_name]
            for a in c_config.attaches:
                a_name = self._policy.cname(map_name, a)
                a_exists = a_name in existing_containers
                if a_exists:
                    a_detail = client.inspect_container(a_name)
                    a_status = a_detail['State']
                    a_image = a_detail['Image']
                    a_remove = (not a_status['Running'] and a_status['ExitCode'] in self.remove_status) or \
                        (self.update_persistent and a_image != self.base_image_ids[client_name])
                    if a_remove:
                        ar_kwargs = self._policy.get_remove_kwargs(c_map, c_config, client_name, client_config, a_name)
                        client.remove_container(**ar_kwargs)
                        existing_containers.remove(a_name)
                else:
                    a_remove = False
                    a_detail = None
                if a_remove or not a_exists:
                    ac_kwargs = self._policy.get_attached_create_kwargs(c_map, c_config, client_name, client_config,
                                                                        a_name, a)
                    client.create_container(**ac_kwargs)
                    existing_containers.add(a_name)
                    as_kwargs = self._policy.get_attached_start_kwargs(c_map, c_config, client_name, client_config,
                                                                       a_name, a)
                    client.start(**as_kwargs)
                    self.prepare_container(images, client, c_map, c_config, client_name, client_config, a, a_name)
                else:
                    volumes = a_detail.get('Volumes')
                    if volumes:
                        mapped_path = a_paths[a]
                        self.path_vfs[a, None, mapped_path] = volumes.get(mapped_path)
            image_name = self.iname_tag(c_config.image or container_name, container_map=c_map)
            image_id = self._policy.images[client_name].ensure_image(image_name, pull_latest=self.pull_latest)
            for ci in instances:
                ci_name = self._policy.cname(map_name, container_name, ci)
                ci_exists = ci_name in existing_containers
                if ci_exists:
                    ci_detail = client.inspect_container(ci_name)
                    ci_status = ci_detail['State']
                    ci_image = ci_detail['Image']
                    ci_volumes = ci_detail.get('Volumes') or {}
                    ci_links = ci_detail['HostConfig']['Links'] or []
                    ci_running = ci_status['Running']
                    ci_remove = (not ci_running and ci_status['ExitCode'] in self.remove_status) or \
                        ((not c_config.persistent or self.update_persistent) and ci_image != image_id) or \
                        not self._check_volumes(c_map, c_config, container_name, ci, ci_volumes) or \
                        not self._check_links(map_name, c_config, ci_links)
                    if ci_remove:
                        if ci_running:
                            ip_kwargs = self._policy.get_stop_kwargs(c_map, c_config, client_name, client_config,
                                                                     ci_name, ci)
                            client.stop(**ip_kwargs)
                        ir_kwargs = self._policy.get_remove_kwargs(c_map, c_config, client_name, client_config, ci_name)
                        client.remove_container(**ir_kwargs)
                        existing_containers.remove(ci_name)<commit_msg>Added update check for command, environment, and network.<commit_after># -*- coding: utf-8 -*-
from __future__ import unicode_literals

import shlex
import six

from ...functional import resolve_value
from .base import AttachedPreparationMixin, ForwardActionGeneratorMixin, AbstractActionGenerator
from .utils import is_initial, get_port_bindings, get_host_binds


def _check_environment(c_config, instance_detail):
    def _parse_env():
        for env_str in instance_env:
            var_name, sep, env_val = env_str.partition('=')
            if sep:
                yield var_name, env_val

    if not c_config.create_options:
        return True
    instance_env = instance_detail['Config']['Env'] or []
    config_env = c_config.create_options.get('environment')
    if not config_env:
        return True
    current_env = dict(_parse_env())
    for k, v in six.iteritems(config_env):
        if current_env.get(k) != v:
            return False
    return True


def _check_cmd(c_config, instance_detail):
    if not c_config.create_options:
        return True
    instance_config = instance_detail['Config']
    config_cmd = c_config.create_options.get('command') if c_config.create_options else None
    if config_cmd:
        instance_cmd = instance_config['Cmd'] or []
        if isinstance(config_cmd, six.string_types):
            if shlex.split(config_cmd) != instance_cmd:
                return False
        elif list(config_cmd) != instance_cmd:
            return False
    config_entrypoint = c_config.create_options.get('entrypoint') if c_config.create_options else None
    if config_entrypoint:
        instance_entrypoint = instance_config['Entrypoint'] or []
        if isinstance(config_entrypoint, six.string_types):
            if [config_entrypoint] != instance_entrypoint:
                return False
        elif list(config_entrypoint) != instance_entrypoint:
            return False
    return True


def _check_network(container_config, client_config, instance_detail):
    if not container_config.exposes:
        return True
    instance_ports = instance_detail['NetworkSettings']['Ports'] or {}
    for port_binding in container_config.exposes:
        port = port_binding.exposed_port
        i_key = port if isinstance(port, six.string_types) and '/' in port else '{0}/tcp'.format(port)
        if i_key not in instance_ports:
            return False
        i_val = instance_ports[i_key]
        bind_port = resolve_value(port_binding.host_port)
        if bind_port:
            if not i_val:
                return False
            interface = resolve_value(port_binding.interface)
            if interface:
                bind_addr = resolve_value(client_config.interfaces.get(interface))
            else:
                bind_addr = '0.0.0.0'
            if {'HostIp': bind_addr, 'HostPort': six.text_type(bind_port)} not in i_val:
                return False
    return True


class ContainerUpdateGenerator(AttachedPreparationMixin, ForwardActionGeneratorMixin, AbstractActionGenerator):
    def __init__(self, policy, *args, **kwargs):
        super(ContainerUpdateGenerator, self).__init__(policy, *args, **kwargs)
        self.remove_status = policy.remove_status
        self.pull_latest = policy.pull_latest
        self.update_persistent = policy.update_persistent
        self.base_image_ids = {
            client_name: policy.images[client_name].ensure_image(
                self.iname_tag(policy.base_image), pull_latest=self.pull_latest)
            for client_name in policy.clients.keys()
        }
        self.path_vfs = {}

    def _check_links(self, map_name, c_config, instance_detail):
        def _extract_link_info(host_link):
            link_name, __, link_alias = host_link.partition(':')
            return link_name[1:], link_alias.rpartition('/')[2]

        instance_links = instance_detail['HostConfig']['Links'] or []
        linked_dict = dict(map(_extract_link_info, instance_links))
        for link in c_config.links:
            if link.alias != linked_dict.get(self._policy.cname(map_name, link.container)):
                return False
        return True

    def _check_volumes(self, c_map, c_config, config_name, instance_name, instance_detail):
        def _validate_bind(b_config, b_instance):
            for host_path, bind_ro in six.iteritems(get_host_binds(c_map, b_config, b_instance)):
                bind_path = bind_ro['bind']
                bind_vfs = instance_volumes.get(bind_path)
                if not (bind_vfs and host_path == bind_vfs):
                    return False
                self.path_vfs[config_name, instance_name, bind_path] = bind_vfs
            return True

        def _validate_attached(a_config):
            for attached in a_config.attaches:
                attached_path = resolve_value(c_map.volumes[attached])
                attached_vfs = instance_volumes.get(attached_path)
                if not (attached_vfs and self.path_vfs.get((attached, None, attached_path)) == attached_vfs):
                    return False
                self.path_vfs[config_name, instance_name, attached_path] = attached_vfs
            return True

        def _check_config_paths(cr_config, cr_instance):
            for share in cr_config.shares:
                cr_shared_path = resolve_value(share)
                self.path_vfs[config_name, instance_name, cr_shared_path] = instance_volumes.get(share)
            if not _validate_bind(cr_config, cr_instance):
                return False
            if not _validate_attached(cr_config):
                return False
            for used in cr_config.uses:
                used_volume = used.volume
                used_path = resolve_value(c_map.volumes.get(used_volume))
                if used_path:
                    if self.path_vfs.get((used_volume, None, used_path)) != instance_volumes.get(used_path):
                        return False
                    continue
                ref_c_name, ref_i_name = self._policy.resolve_cname(used_volume, False)
                ref_config = c_map.get_existing(ref_c_name)
                if ref_config:
                    for share in ref_config.shares:
                        ref_shared_path = resolve_value(share)
                        i_shared_path = instance_volumes.get(ref_shared_path)
                        if self.path_vfs.get((ref_c_name, ref_i_name, ref_shared_path)) != i_shared_path:
                            return False
                        self.path_vfs[(config_name, instance_name, ref_shared_path)] = i_shared_path
                    _validate_bind(ref_config, ref_i_name)
                    _validate_attached(ref_config)
                else:
                    raise ValueError("Volume alias or container reference could not be resolved: {0}".format(used))
            return True

        instance_volumes = instance_detail.get('Volumes') or {}
        return _check_config_paths(c_config, instance_name)

    def iname_tag(self, image, container_map=None):
        i_name = '{0}:latest'.format(image) if ':' not in image else image
        if container_map:
            return self._policy.iname(container_map, i_name)
        return i_name

    def generate_item_actions(self, map_name, c_map, container_name, c_config, instances, flags, *args, **kwargs):
        a_paths = {alias: resolve_value(c_map.volumes[alias]) for alias in c_config.attaches}
        for client_name, client, client_config in self._policy.get_clients(c_config, c_map):
            images = self._policy.images[client_name]
            existing_containers = self._policy.container_names[client_name]
            for a in c_config.attaches:
                a_name = self._policy.cname(map_name, a)
                a_exists = a_name in existing_containers
                if a_exists:
                    a_detail = client.inspect_container(a_name)
                    a_status = a_detail['State']
                    a_image = a_detail['Image']
                    a_remove = (not a_status['Running'] and a_status['ExitCode'] in self.remove_status) or \
                        (self.update_persistent and a_image != self.base_image_ids[client_name])
                    if a_remove:
                        ar_kwargs = self._policy.get_remove_kwargs(c_map, c_config, client_name, client_config, a_name)
                        client.remove_container(**ar_kwargs)
                        existing_containers.remove(a_name)
                else:
                    a_remove = False
                    a_detail = None
                if a_remove or not a_exists:
                    ac_kwargs = self._policy.get_attached_create_kwargs(c_map, c_config, client_name, client_config,
                                                                        a_name, a)
                    client.create_container(**ac_kwargs)
                    existing_containers.add(a_name)
                    as_kwargs = self._policy.get_attached_start_kwargs(c_map, c_config, client_name, client_config,
                                                                       a_name, a)
                    client.start(**as_kwargs)
                    self.prepare_container(images, client, c_map, c_config, client_name, client_config, a, a_name)
                else:
                    volumes = a_detail.get('Volumes')
                    if volumes:
                        mapped_path = a_paths[a]
                        self.path_vfs[a, None, mapped_path] = volumes.get(mapped_path)
            image_name = self.iname_tag(c_config.image or container_name, container_map=c_map)
            image_id = self._policy.images[client_name].ensure_image(image_name, pull_latest=self.pull_latest)
            for ci in instances:
                ci_name = self._policy.cname(map_name, container_name, ci)
                ci_exists = ci_name in existing_containers
                if ci_exists:
                    ci_detail = client.inspect_container(ci_name)
                    ci_status = ci_detail['State']
                    ci_image = ci_detail['Image']
                    ci_running = ci_status['Running']
                    ci_remove = (not ci_running and ci_status['ExitCode'] in self.remove_status) or \
                        ((not c_config.persistent or self.update_persistent) and ci_image != image_id) or \
                        not self._check_volumes(c_map, c_config, container_name, ci, ci_detail) or \
                        not self._check_links(map_name, c_config, ci_detail) or \
                        not _check_environment(c_config, ci_detail) or \
                        not _check_cmd(c_config, ci_detail) or \
                        not _check_network(c_config, client_config, ci_detail)
                    if ci_remove:
                        if ci_running:
                            ip_kwargs = self._policy.get_stop_kwargs(c_map, c_config, client_name, client_config,
                                                                     ci_name, ci)
                            client.stop(**ip_kwargs)
                        ir_kwargs = self._policy.get_remove_kwargs(c_map, c_config, client_name, client_config, ci_name)
                        client.remove_container(**ir_kwargs)
                        existing_containers.remove(ci_name)
{'fraction_non_alphanumeric': 0.07631896898912606, 'fraction_numerical': 0.0007551349174385823, 'mean_word_length': 1.9769219241720366, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 1, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 18, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4202988', 'n_tokens_mistral': 5558, 'n_tokens_neox': 5351, 'n_words': 1091}