def _service_restart_policy(self, restart_policy_dict: Dict) -> None: """ Converts the parameters in deploy[restart_policy] into a RestartPolicy class as expected by docker-py lib. """ self.restart_policy = RestartPolicy( condition=restart_policy_dict.get('condition') or 'none', delay=convert_time_to_secs(restart_policy_dict.get('delay')) or 0, max_attempts=restart_policy_dict.get('max_attempts') or 0, window=convert_time_to_secs(restart_policy_dict.get('window')) or 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_service_restart_policy(self): restart_policy = { 'restart_policy': { 'condition': 'none', 'delay': '3s', 'max_attempts': 5, 'window': 0 } } svc = Service(name=self.svc_name, deploy=restart_policy) rest_config = RestartPolicy(condition='none', delay=3, max_attempts=5, window=0) self.assertEquals(svc.restart_policy, rest_config)
def test_service_restart_policy_with_additional_parameters(self): restart_policy = { 'restart_policy': { 'condition': 'none', 'delay': '3s', 'max_attempts': 5, 'test': 'unused_parameter' } } svc = Service(name=self.svc_name, deploy=restart_policy) rest_config = RestartPolicy(condition='none', delay=3, max_attempts=5, window=0) self.assertEquals(svc.restart_policy, rest_config)
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
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 }