Ejemplo n.º 1
0
    def _launch_nested_container_session(self):
        """Sends a request to the Mesos Agent to launch a new
        nested container and attach to its output stream.
        The output stream is then sent back in the response.
        """

        message = {
            'type': "LAUNCH_NESTED_CONTAINER_SESSION",
            'launch_nested_container_session': {
                'container_id': {
                    'parent': { 'value': self.parent_id },
                    'value': self.container_id
                },
                'command': {
                    'value': self.cmd,
                    'arguments': [self.cmd] + self.args,
                    'shell': False}}}
        # If we have to launch in a task group, we need double nesting
        if self.parent_container_id is not None:
            message['launch_nested_container_session']['container_id']['parent']['parent'] = { 'value': self.parent_container_id }
        if self.env is not None:
            env_vars = []
            env_var_regex = re.compile('^([A-Z_][A-Z0-9_]*)=(.*)$')
            for env_var in self.env.split(':'):
                matches = env_var_regex.match(env_var)
                if matches and len(matches.groups()) == 2:
                    env_vars.append({
                        'name': matches.group(1),
                        'type': 'VALUE',
                        'value': matches.group(2)
                    })
            message['launch_nested_container_session']['command']['environment'] = {
                'variables': env_vars
            }

        if not self.user is None:
          message['launch_nested_container_session']['command']['user'] =\
             self.user

        if self.tty:
            message[
                'launch_nested_container_session'][
                    'container'] = {
                        'type': 'MESOS',
                        'tty_info': {}}

        req_extra_args = {
            'stream': True,
            'headers': {
                'Content-Type': 'application/json',
                'Accept': 'application/recordio',
                'Message-Accept': 'application/json'}}

        response = http.post(
            self.agent_url,
            data=json.dumps(message),
            timeout=None,
            **req_extra_args)

        self._process_output_stream(response)
Ejemplo n.º 2
0
    def _launch_nested_container_session(self):
        """Sends a request to the Mesos Agent to launch a new
        nested container and attach to its output stream.
        The output stream is then sent back in the response.
        """

        message = {
            'type': "LAUNCH_NESTED_CONTAINER_SESSION",
            'launch_nested_container_session': {
                'container_id': {
                    'parent': {
                        'value': self.parent_id
                    },
                    'value': self.container_id
                },
                'command': {
                    'value': self.cmd,
                    'arguments': [self.cmd] + self.args,
                    'shell': False
                }
            }
        }
        if not self.user is None:
            message['launch_nested_container_session']['command']['user'] =\
               self.user

        if self.tty:
            message['launch_nested_container_session']['container'] = {
                'type': 'MESOS',
                'tty_info': {}
            }

        req_extra_args = {
            'stream': True,
            'headers': {
                'Content-Type': 'application/json',
                'Accept': 'application/recordio',
                'Message-Accept': 'application/json'
            }
        }

        response = http.post(self.agent_url,
                             data=json.dumps(message),
                             timeout=None,
                             **req_extra_args)

        self._process_output_stream(response)
Ejemplo n.º 3
0
    def _attach_container_input(self):
        """Streams all input data (e.g. STDIN) from the client to the agent
        """
        def _initial_input_streamer():
            """Generator function yielding the initial ATTACH_CONTAINER_INPUT
            message for streaming. We have a separate generator for this so
            that we can attempt the connection once before committing to a
            persistent connection where we stream the rest of the input.

            :returns: A RecordIO encoded message
            """

            message = {
                'type': 'ATTACH_CONTAINER_INPUT',
                'attach_container_input': {
                    'type': 'CONTAINER_ID',
                    'container_id': {
                        'parent': {
                            'value': self.parent_id
                        },
                        'value': self.container_id
                    }
                }
            }

            yield self.encoder.encode(message)

        def _input_streamer():
            """Generator function yielding ATTACH_CONTAINER_INPUT
            messages for streaming. It yields the _intitial_input_streamer()
            message, followed by messages from the input_queue on each
            subsequent call.

            :returns: A RecordIO encoded message
            """

            yield next(_initial_input_streamer())

            while True:
                record = self.input_queue.get()
                if not record:
                    break
                yield record

        req_extra_args = {
            'headers': {
                'Content-Type': 'application/recordio',
                'Message-Content-Type': 'application/json',
                'Accept': 'application/json',
                'Connection': 'close',
                'Transfer-Encoding': 'chunked'
            }
        }

        # Ensure we don't try to attach our input to a container that isn't
        # fully up and running by waiting until the
        # `_process_output_stream` function signals us that it's ready.
        self.attach_input_event.wait()

        # Send an intial "Test" message to ensure that we are able to
        # establish a connection with the agent. If we aren't we will throw
        # an exception and break out of this thread. However, in cases where
        # we receive a 500 response from the agent, we actually want to
        # continue without throwing an exception. A 500 error indicates that
        # we can't connect to the container because it has already finished
        # running. In that case we continue running to allow the output queue
        # to be flushed.
        try:
            http.post(self.agent_url,
                      data=_initial_input_streamer(),
                      **req_extra_args)
        except MesosHTTPException as e:
            if not e.response.status_code == 500:
                raise e

        # If we succeeded with that connection, unblock process_output_stream()
        # from sending output data to the output thread.
        self.print_output_event.set()

        # Begin streaming the input.
        http.post(self.agent_url,
                  data=_input_streamer(),
                  timeout=None,
                  **req_extra_args)