Ejemplo n.º 1
0
 def update(self, service_name, image_id=None, scale=None):
     """
     update the given service with the given image
     :param image_id:
     :return:
     """
     logger.info("upgrading %s to %s scale=%s", service_name, image_id, scale)
     service = self._get(service_name=service_name)
     attrs = {}
     if image_id is not None:
         attrs['image'] = image_id
     if scale is not None:
         if scale == -1:
             attrs['mode'] = ServiceMode('global', 1)
         else:
             attrs['mode'] = ServiceMode('replicated', scale)
     service.update(fetch_current_spec=True, **attrs)
Ejemplo n.º 2
0
 def _service_mode(self, mode: Dict) -> None:
     """
     Converts a couple of parameters - deploy['mode'] and deploy['replicas']
     into a ServiceMode class as expected by docker-py lib.
     Defaults to a 'replicated' service with 1 replica.
     """
     svc_mode = mode.get('mode') or Modes.REPLICATED
     svc_replicas = mode.get('replicas') or 1 \
         if svc_mode != Modes.GLOBAL else None
     self.mode = ServiceMode(mode=svc_mode, replicas=svc_replicas)
Ejemplo n.º 3
0
    def _send_signal_in_swarm(self):
        current_container_id = get_current_container_id()
        if not current_container_id:
            return

        current_container = self.client.containers.get(current_container_id)
        if not current_container:
            return

        image = current_container.attrs['Config'].get('Image')
        if not image:
            return

        command = [sys.executable, __file__, '--label', self.label_name]

        log_driver = current_container.attrs['HostConfig']['LogConfig']['Type']
        log_config = current_container.attrs['HostConfig']['LogConfig'][
            'Config']

        sender = self.client.services.create(
            image=image,
            command=command,
            name='domain-automation-signal-%d-%d' %
            (int(time.time() * 1000), random.randint(100, 999)),
            env=['PYTHONPATH=%s' % os.environ.get('PYTHONPATH', '.')],
            log_driver=log_driver,
            log_driver_options=log_config,
            mode=ServiceMode('global'),
            restart_policy=RestartPolicy(condition='none', max_attempts=0),
            mounts=['/var/run/docker.sock:/var/run/docker.sock:ro'])

        max_wait = 60
        start_time = time.time()

        while abs(time.time() - start_time) < max_wait:
            if all(task['DesiredState'] == 'shutdown'
                   for task in sender.tasks()):
                break

            time.sleep(1)

        states = list(task['Status']['State'] for task in sender.tasks())
        logs = ''.join(
            item.decode() if hasattr(item, 'decode') else item
            for item in sender.logs(stdout=True, stderr=True)).strip()

        sender.remove()

        logger.info('Signalled containers with label %s - result: %s' %
                    (self.label_name, ', '.join(map(str, states))))

        if logs:
            logger.info('Signal logs: %s' % logs)
    def test_scale_method_global_service(self):
        client = docker.from_env(version=TEST_API_VERSION)
        mode = ServiceMode('global')
        service = client.services.create(name=helpers.random_name(),
                                         image="alpine",
                                         command="sleep 300",
                                         mode=mode)
        tasks = []
        while len(tasks) == 0:
            tasks = service.tasks()
        assert len(tasks) == 1
        with pytest.raises(InvalidArgument):
            service.scale(2)

        assert len(tasks) == 1
        service.reload()
        spec = service.attrs['Spec']['TaskTemplate']['ContainerSpec']
        assert spec.get('Command') == ['sleep', '300']
Ejemplo n.º 5
0
    def deploy_VDU(self,
                   name,
                   sw_image,
                   networks,
                   placement_policy,
                   app="sleep infinity",
                   arguments=None,
                   endpoint=None,
                   mode="replicated",
                   replicas=1):
        """

        :param name:
        :param sw_image:
        :param networks:
        :param placement_policy:
        :param mode:
        :param replicas:
        :return:
        """
        placement_constraints = []
        if placement_policy is not None:
            for constraint in placement_policy:
                label, value = constraint.split("==")
                label = "node.labels." + label
                placement_constraints.append(label + "==" + value)
        oneRep = ServiceMode(mode, replicas)
        service_port = None
        if endpoint is not None:
            service_port = docker.types.EndpointSpec(
                mode='vip', ports={endpoint: endpoint})
        docker_vdu = client.services.create(sw_image,
                                            command=app,
                                            args=arguments,
                                            name=name,
                                            networks=networks,
                                            mode=oneRep,
                                            constraints=placement_constraints,
                                            endpoint_spec=service_port)
Ejemplo n.º 6
0
    def configure(cls, image, service, secrets=None, mounts=None, **kwargs):
        self = ServiceKwargs()
        options = service.options
        deploy_opts = options.get("deploy", {})
        prefs = deploy_opts.get("placement", {}).get("preferences", {})

        # Map compose options to service options
        self.image = image
        self.constraints = deploy_opts.get("placement", {}).get("constraints")
        self.preferences = [kv for pref in prefs for kv in pref.items()]
        self.container_labels = options.get("labels")

        self.endpoint_spec = EndpointSpec(
            deploy_opts.get("endpoint_mode"),
            {p.published: p.target
             for p in options.get("ports", [])})

        self.env = options.get("environment", None)
        self.hostname = options.get("hostname")
        self.isolation = options.get("isolation")
        self.labels = {
            k: v
            for k, v in (kv.split('=') for kv in deploy_opts.get("labels", []))
        }
        self.log_driver = options.get("logging", {}).get("driver")
        self.log_driver_options = options.get("logging", {}).get("options")
        self.mode = ServiceMode(deploy_opts.get("mode", "replicated"),
                                deploy_opts.get("replicas", 1))
        self.networks = [
            config.SWARM_NETWORK
        ]  # Similar to mounts. I don't see the use case but see the issues

        resource_opts = deploy_opts.get("resources", {})
        if resource_opts:
            # Unpack any generic_resources defined i.e. gpus and such
            reservation_opts = resource_opts.get("reservations", {})
            generic_resources = {}
            for generic_resource in reservation_opts.get(
                    "generic_resources", {}):
                discrete_resource_spec = generic_resource[
                    "discrete_resource_spec"]
                generic_resources[discrete_resource_spec[
                    "kind"]] = discrete_resource_spec["value"]
            cpu_limit = sfloat(resource_opts.get("limits", {}).get("cpus"), 0)
            cpu_reservation = sfloat(reservation_opts.get("cpus"), 0)
            nano_cpu_limit = sint(cpu_limit *
                                  1e9, 0) if cpu_limit is not None else None
            nano_cpu_reservation = sint(
                cpu_reservation *
                1e9, 0) if cpu_reservation is not None else None
            self.resources = Resources(
                cpu_limit=nano_cpu_limit,
                mem_limit=parse_bytes(
                    resource_opts.get("limits", {}).get("memory", '')),
                cpu_reservation=nano_cpu_reservation,
                mem_reservation=parse_bytes(reservation_opts.get("memory",
                                                                 '')),
                generic_resources=generic_resources)

        restart_opts = deploy_opts.get("restart_policy", {})
        if restart_opts:
            # Parse the restart policy
            delay = timeparse(restart_opts.get("delay", "0s"))
            window = timeparse(restart_opts.get("restart_opts", "0s"))
            self.restart_policy = RestartPolicy(
                condition=restart_opts.get("condition", ),
                delay=delay,
                max_attempts=sint(restart_opts.get("max_attempts", 0), 0),
                window=window)

        self.secrets = secrets
        self.mounts = mounts

        # Grab any key word arguments that may have been given
        [setattr(self, k, v) for k, v in kwargs.items() if hasattr(self, k)]

        service_kwargs = _get_create_service_kwargs('create',
                                                    copy.copy(self.__dict__))

        # This is needed because aiodocker assumes the Env is a dictionary for some reason...
        if self.env is not None:
            service_kwargs["task_template"]["ContainerSpec"]["Env"] = self.env

        return service_kwargs
Ejemplo n.º 7
0
    def configure(self, service, secrets=None):
        """ Parameters:
                image (str) – The image name to use for the containers.
                command (list of str or str) – Command to run.
                args (list of str) – Arguments to the command.
                constraints (list of str) – Placement constraints.
                preferences (list of tuple) – Placement preferences.
                platforms (list of tuple) – A list of platform constraints expressed as (arch, os) tuples.
                container_labels (dict) – Labels to apply to the container.
                endpoint_spec (EndpointSpec) – Properties that can be configured to access and load balance a service. Default: None.
                env (list of str) – Environment variables, in the form KEY=val.
                hostname (string) – Hostname to set on the container.
                isolation (string) – Isolation technology used by the service’s containers. Only used for Windows containers.
                labels (dict) – Labels to apply to the service.
                log_driver (str) – Log driver to use for containers.
                log_driver_options (dict) – Log driver options.
                mode (ServiceMode) – Scheduling mode for the service. Default:None
                mounts (list of str) – Mounts for the containers, in the form source:target:options, where options is either ro or rw.
                name (str) – Name to give to the service.
                networks (list of str) – List of network names or IDs to attach the service to. Default: None.
                resources (Resources) – Resource limits and reservations.
                restart_policy (RestartPolicy) – Restart policy for containers.
                secrets (list of docker.types.SecretReference) – List of secrets accessible to containers for this service.
                stop_grace_period (int) – Amount of time to wait for containers to terminate before forcefully killing them.
                update_config (UpdateConfig) – Specification for the update strategy of the service. Default: None
                rollback_config (RollbackConfig) – Specification for the rollback strategy of the service. Default: None
                user (str) – User to run commands as.
                workdir (str) – Working directory for commands to run.
                tty (boolean) – Whether a pseudo-TTY should be allocated.
                groups (list) – A list of additional groups that the container process will run as.
                open_stdin (boolean) – Open stdin
                read_only (boolean) – Mount the container’s root filesystem as read only.
                stop_signal (string) – Set signal to stop the service’s containers
                healthcheck (Healthcheck) – Healthcheck configuration for this service.
                hosts (dict) – A set of host to IP mappings to add to the container’s hosts file.
                dns_config (DNSConfig) – Specification for DNS related configurations in resolver configuration file.
                configs (list) – List of ConfigReference that will be exposed to the service.
                privileges (Privileges) – Security options for the service’s containers.
        """

        options = service.options
        deploy_opts = options.get("deploy", {})
        prefs = deploy_opts.get("placement", {}).get("preferences", {})

        # Map compose options to service options
        self.constraints = deploy_opts.get("placement", {}).get("constraints")
        self.preferences = [kv for pref in prefs for kv in pref.items()]
        self.container_labels = options.get("labels")

        self.endpoint_spec = EndpointSpec(
            deploy_opts.get("endpoint_mode"),
            {p.published: p.target
             for p in options.get("ports", [])})

        self.env = [f"{k}={v}" for k, v in options.get("environment").items()]
        self.hostname = options.get("hostname")
        self.isolation = options.get("isolation")
        self.labels = {
            k: v
            for k, v in (kv.split('=') for kv in deploy_opts.get("labels", []))
        }
        self.log_driver = options.get("logging", {}).get("driver")
        self.log_driver_options = options.get("logging", {}).get("options")
        self.mode = ServiceMode(deploy_opts.get("mode", "replicated"),
                                deploy_opts.get("replicas", 1))
        self.mounts = None  # I'm not sure we should allow mounting volumes to apps until I see a use case
        self.name = service.name
        self.networks = None  # Similar to mounts. I don't see the use case but see the issues

        resource_opts = deploy_opts.get("resources", {})
        if resource_opts:
            # Unpack any generic_resources defined i.e. gpus and such
            reservation_opts = resource_opts.get("reservations", {})
            generic_resources = {}
            for generic_resource in reservation_opts.get(
                    "generic_resources", {}):
                discrete_resource_spec = generic_resource[
                    "discrete_resource_spec"]
                generic_resources[discrete_resource_spec[
                    "kind"]] = discrete_resource_spec["value"]
            cpu_limit = sfloat(resource_opts.get("limits", {}).get("cpus"))
            cpu_reservation = sfloat(reservation_opts.get("cpus"))
            nano_cpu_limit = sint(cpu_limit *
                                  1e9) if cpu_limit is not None else None
            nano_cpu_reservation = sint(
                cpu_reservation * 1e9) if cpu_reservation is not None else None
            self.resources = Resources(
                cpu_limit=nano_cpu_limit,
                mem_limit=parse_bytes(
                    resource_opts.get("limits", {}).get("memory", '')),
                cpu_reservation=nano_cpu_reservation,
                mem_reservation=parse_bytes(reservation_opts.get("memory",
                                                                 '')),
                generic_resources=generic_resources)

        restart_opts = deploy_opts.get("restart_policy", {})
        if restart_opts:
            # Parse the restart policy
            delay = timeparse.timeparse(restart_opts.get("delay", "0s"))
            window = timeparse.timeparse(restart_opts.get(
                "restart_opts", "0s"))
            self.restart_policy = RestartPolicy(
                condition=restart_opts.get("condition", ),
                delay=delay,
                max_attempts=sint(restart_opts.get("max_attempts", 0)),
                window=window)

        # self.secrets = [SecretReference(secret_id=s["secret"].uid, secret_name=s["secret"].name, filename=s.get("file", s["secret"].name), uid=s["secret"].uid, gid=s["secret"].gid, mode=s["secret"].mode) for s in service.secrets]
        # self.secrets = self.load_secrets(service)

        return {
            key: value
            for key, value in self.as_dict().items() if value is not None
        }
 def test_service_global_mode(self):
     mode = {'mode': 'global'}
     svc = Service(name=self.svc_name, deploy=mode)
     svc_mode = ServiceMode('global')
     self.assertEquals(svc.mode, svc_mode)
 def test_service_replicas(self):
     replicas = {'replicas': 3}
     svc = Service(name=self.svc_name, deploy=replicas)
     svc_mode = ServiceMode('replicated', 3)
     self.assertEquals(svc.mode, svc_mode)