def proxy(upstream, endpoint, header):
    """
    Establish a new connection to ``endpoint`` and begin proxying between that
    connection and ``upstream``.

    :param IProtocol upstream: A connected protocol.  All data received by
        this protocol from this point on will be sent along to another newly
        established connection.

    :param IStreamClientEndpoint endpoint: An endpoint to use to establish a
        new connection.  All data received over this connection will be sent
        along to the upstream connection.

    :param bytes header: Some extra data to write to the new downstream
        connection before proxying begins.
    """
    def failed(reason):
        upstream.transport.resumeProducing()
        upstream.transport.abortConnection()
        return reason

    upstream.transport.pauseProducing()

    peer = upstream.transport.getPeer()
    action = start_action(action_type=u"grid-router:proxy",
                          **{u"from": (peer.host, peer.port)})
    with action.context():
        d = DeferredContext(endpoint.connect(Factory.forProtocol(_Proxy)))
        d.addCallbacks(
            lambda downstream: DeferredContext(
                downstream.take_over(upstream, header)),
            failed,
        )
        return d.addActionFinish()
Beispiel #2
0
 def packet_proxy(self, unwrapped_packet):
     """
     receive the unwrapped packet and append it to the batch.
     if the threshold is reached then we shuffle the batch
     and send the batch out after a random delay.
     """
     assert isinstance(unwrapped_packet, UnwrappedMessage)
     if unwrapped_packet.next_hop:
         action = start_action(
             action_type=u"proxy unwrapped packet to next hop",
         )
         with action.context():
             destination, sphinx_packet = unwrapped_packet.next_hop
             d = self.sphinx_packet_send(destination, sphinx_packet)
             DeferredContext(d).addActionFinish()
     elif unwrapped_packet.client_hop:
         action = start_action(
             action_type=u"proxy unwrapped packet to client hop",
         )
         with action.context():
             d = self.forward_to_client(*unwrapped_packet.client_hop)
             DeferredContext(d).addActionFinish()
     elif unwrapped_packet.exit_hop:
         raise UnimplementedError()
     else:
         raise InvalidSphinxPacketError()
     return d
Beispiel #3
0
    def _stopInstance(self):
        """
        Shutdown the slave and then stop the instance.

        We need to do both, to avoid the following sequence:
        - Shutdown instance
        - Pending build triggers new instance
        - When new slave connects, duplicate slave detection kicks in, causing
          the original slave to disconnect. That disconnect triggers the new
          slave instance to shutdown.
        - Loop.

        https://clusterhq.atlassian.net/browse/FLOC-1938
        """
        with start_action(
                action_type="ondemand_slave:stop_instance",
                slave=self.slavename,
        ).context():
            with start_action(action_type="ondemand_slave:shutdown").context():
                d = DeferredContext(self.shutdown())
                timeoutDeferred(reactor, d, 60)
                d = d.addActionFinish()
            d = DeferredContext(d)
            d.addBoth(lambda _: self.instance_booter.stop())
            d.addActionFinish()
Beispiel #4
0
    def add_file(self,
                 namex,
                 uploadable,
                 metadata=None,
                 overwrite=True,
                 progress=None):
        """I upload a file (using the given IUploadable), then attach the
        resulting FileNode to the directory at the given name. I return a
        Deferred that fires (with the IFileNode of the uploaded file) when
        the operation completes."""
        with ADD_FILE(name=namex, metadata=metadata,
                      overwrite=overwrite).context():
            name = normalize(namex)
            if self.is_readonly():
                d = DeferredContext(defer.fail(NotWriteableError()))
            else:
                # XXX should pass reactor arg
                d = DeferredContext(
                    self._uploader.upload(uploadable, progress=progress))
                d.addCallback(lambda results: self._create_and_validate_node(
                    results.get_uri(), None, name))
                d.addCallback(lambda node: self.set_node(
                    name, node, metadata, overwrite))

        return d.addActionFinish()
Beispiel #5
0
def sample(operation, metric, name):
    """
    Perform sampling of the operation.

    :param IOperation operation: An operation to perform.
    :param IMetric metric: A quantity to measure.
    :param int name: Identifier for individual sample.
    :return: Deferred firing with a sample. A sample is a dictionary
        containing a ``success`` boolean.  If ``success is True``, the
        dictionary also contains a ``value`` for the sample measurement.
        If ``success is False``, the dictionary also contains a
        ``reason`` for failure.
    """
    with start_action(action_type=u'flocker:benchmark:sample', sample=name):
        sampling = DeferredContext(maybeDeferred(operation.get_probe))

        def run_probe(probe):
            probing = metric.measure(probe.run)
            probing.addCallbacks(
                lambda interval: dict(success=True, value=interval),
                lambda reason: dict(success=False,
                                    reason=reason.getTraceback()),
            )
            probing.addCallback(bypass, probe.cleanup)

            return probing

        sampling.addCallback(run_probe)
        sampling.addActionFinish()
        return sampling.result
def _get_converge_inputs(config, subscriptions, k8s, aws):
    a = start_action(action_type=u"load-converge-inputs")
    with a.context():
        d = DeferredContext(
            gatherResults([
                get_active_subscriptions(subscriptions),
                get_customer_grid_configmaps(k8s, config.kubernetes_namespace),
                get_customer_grid_deployments(k8s, config.kubernetes_namespace),
                get_customer_grid_replicasets(k8s, config.kubernetes_namespace),
                get_customer_grid_pods(k8s, config.kubernetes_namespace),
                get_customer_grid_service(k8s, config.kubernetes_namespace),
                get_hosted_zone_by_name(aws.get_route53_client(), Name(config.domain)),
            ]),
        )
        d.addCallback(
            lambda state: _State(**dict(
                zip([
                    u"subscriptions",
                    u"configmaps",
                    u"deployments",
                    u"replicasets",
                    u"pods",
                    u"service",
                    u"zone",
                ], state,
                ),
            )),
        )
        return d.addActionFinish()
def get_hosted_zone_by_name(route53, name):
    """
    Get a ``HostedZone`` with a zone name matching ``name``.

    :param route53: A txaws Route53 client.

    :param txaws.route53.model.Name name: The zone name to look for.

    :raise KeyError: If no matching hosted zone is found.

    :return Deferred(HostedZone): The hosted zone with a matching name.
    """
    action = start_action(action_type=u"get-hosted-zone")
    with action.context():
        d = DeferredContext(route53.list_hosted_zones())
        def filter_results(zones):
            Message.log(zone_names=list(zone.name for zone in zones))
            for zone in zones:
                # XXX Bleuch zone.name should be a Name!
                if Name(zone.name) == name:
                    d = route53.list_resource_record_sets(zone_id=zone.identifier)
                    d.addCallback(
                        lambda rrsets, zone=zone: _ZoneState(
                            zone=zone,
                            rrsets=rrsets,
                        ),
                    )
                    return d
            raise KeyError(name)
        d.addCallback(filter_results)
        return d.addActionFinish()
Beispiel #8
0
    def _async_get_node(self, reactor, instance, metadata):
        """
        Configure the given AWS instance, wait until it's running
        and create an ``AWSNode`` object for it.

        :param reactor: The reactor.
        :param boto.ec2.instance.Instance instance: The instance to set up.
        :param dict metadata: The metadata to set for the instance.
        :return: Deferred that fires when the instance is ready.
        """
        def instance_error(failure):
            Message.log(
                message_type="flocker:provision:aws:async_get_node:failed")
            instance.terminate()
            write_failure(failure)
            return failure

        action = start_action(
            action_type=u"flocker:provision:aws:async_get_node",
            name=metadata['Name'],
            instance_id=instance.id,
        )
        with action.context():
            d = loop_until(
                reactor,
                lambda: maybeDeferred(self._set_metadata, instance, metadata),
                repeat(5, INSTANCE_TIMEOUT),
            )
            d = DeferredContext(d)
            d.addCallback(
                lambda _: _async_wait_until_running(reactor, instance))
            d.addErrback(instance_error)
            d.addActionFinish()
            return d.result
Beispiel #9
0
        def got_local_state(state_changes):
            # Current cluster state is likely out of date as regards the local
            # state, so update it accordingly.
            #
            # XXX This somewhat side-steps the whole explicit-state-machine
            # thing we're aiming for here.  It would be better for these state
            # changes to arrive as an input to the state machine.
            for state in state_changes:
                self.cluster_state = state.update_cluster_state(
                    self.cluster_state)

            # XXX And for this update to be the side-effect of an output
            # resulting.
            sent_state = self._maybe_send_state_to_control_service(
                state_changes)

            action = self.deployer.calculate_changes(self.configuration,
                                                     self.cluster_state)
            LOG_CALCULATED_ACTIONS(calculated_actions=action).write(
                self.fsm.logger)
            ran_state_change = run_state_change(action, self.deployer)
            DeferredContext(ran_state_change).addErrback(
                writeFailure, self.fsm.logger)

            # Wait for the control node to acknowledge the new
            # state, and for the convergence actions to run.
            return gather_deferreds([sent_state, ran_state_change])
Beispiel #10
0
    def volumedriver_list(self):
        """
        Return information about the current state of all volumes.

        :return: Result indicating success.
        """
        listing = DeferredContext(
            self._flocker_client.list_datasets_configuration())

        def got_configured(configured):
            results = []
            for dataset in configured:
                # Datasets without a name can't be used by the Docker plugin:
                if NAME_FIELD not in dataset.metadata:
                    continue
                dataset_name = dataset.metadata[NAME_FIELD]
                d = self._get_path_from_dataset_id(dataset.dataset_id)
                d.addCallback(lambda path, name=dataset_name: (path, name))
                results.append(d)
            return gatherResults(results)

        listing.addCallback(got_configured)

        def got_paths(results):
            return {u"Err": u"",
                    u"Volumes": sorted([
                        {u"Name": name,
                         u"Mountpoint": u"" if path is None else path.path}
                        for (path, name) in results])}
        listing.addCallback(got_paths)
        return listing.result
Beispiel #11
0
 def _test_registration(self):
     return (
         DeferredContext(self._test_create_client())
         .addCallback(partial(setattr, self, 'client'))
         .addCallback(lambda _: self._test_register())
         .addCallback(tap(
             lambda reg1: self.assertEqual(reg1.body.contact, ())))
         .addCallback(tap(
             lambda reg1:
             self._test_register(
                 NewRegistration.from_data(email=u'*****@*****.**'))
             .addCallback(tap(
                 lambda reg2: self.assertEqual(reg1.uri, reg2.uri)))
             .addCallback(lambda reg2: self.assertEqual(
                 reg2.body.contact, (u'mailto:[email protected]',)))))
         .addCallback(self._test_agree_to_tos)
         .addCallback(
             lambda _: self._test_request_challenges(self.HOST))
         .addCallback(partial(setattr, self, 'authzr'))
         .addCallback(lambda _: self._create_responder())
         .addCallback(tap(lambda _: self._test_poll_pending(self.authzr)))
         .addCallback(self._test_answer_challenge)
         .addCallback(tap(lambda _: self._test_poll(self.authzr)))
         .addCallback(lambda stop_responding: stop_responding())
         .addCallback(lambda _: self._test_issue(self.HOST))
         .addCallback(self._test_chain)
         .addActionFinish())
Beispiel #12
0
    def logger(self, request, **routeArguments):
        logger = _get_logger(self)

        # If this is ever more than ASCII we might have issues? or maybe
        # this is pre-url decoding?
        # https://clusterhq.atlassian.net/browse/FLOC-1602
        action = REQUEST(logger,
                         request_path=request.path,
                         method=request.method)

        # Generate a serialized action context that uniquely identifies
        # position within the logs, though there won't actually be any log
        # message with that particular task level:
        incidentIdentifier = action.serialize_task_id()

        with action.context():
            d = DeferredContext(original(self, request, **routeArguments))

        def failure(reason):
            if reason.check(BadRequest):
                code = reason.value.code
                result = reason.value.result
            else:
                writeFailure(reason, logger, LOG_SYSTEM)
                code = INTERNAL_SERVER_ERROR
                result = incidentIdentifier
            request.setResponseCode(code)
            request.responseHeaders.setRawHeaders(b"content-type",
                                                  [b"application/json"])
            return dumps(result)

        d.addErrback(failure)
        d.addActionFinish()
        return d.result
Beispiel #13
0
    def volumedriver_get(self, Name):
        """
        Return information about the current state of a particular volume.

        :param unicode Name: The name of the volume.

        :return: Result indicating success.
        """
        d = DeferredContext(self._dataset_id_for_name(Name))
        d.addCallback(self._get_path_from_dataset_id)

        def got_path(path):
            if path is None:
                path = u""
            else:
                path = path.path
            return {
                u"Err": u"",
                u"Volume": {
                    u"Name": Name,
                    u"Mountpoint": path
                }
            }

        d.addCallback(got_path)
        return d.result
Beispiel #14
0
    def volumedriver_mount(self, Name):
        """
        Move a volume with the given name to the current node and mount it.

        Since we need to return the filesystem path we wait until the
        dataset is mounted locally.

        :param unicode Name: The name of the volume.

        :return: Result that includes the mountpoint.
        """
        d = DeferredContext(self._dataset_id_for_name(Name))
        d.addCallback(lambda dataset_id: self._flocker_client.move_dataset(
            self._node_id, dataset_id))
        d.addCallback(lambda dataset: dataset.dataset_id)

        d.addCallback(lambda dataset_id: loop_until(
            self._reactor, lambda: self._get_path_from_dataset_id(dataset_id),
            repeat(self._POLL_INTERVAL)))
        d.addCallback(lambda p: {u"Err": None, u"Mountpoint": p.path})

        timeout(self._reactor, d.result, self._MOUNT_TIMEOUT)

        def handleCancel(failure):
            failure.trap(CancelledError)
            return {
                u"Err": u"Timed out waiting for dataset to mount.",
                u"Mountpoint": u""
            }

        d.addErrback(handleCancel)
        return d.result
Beispiel #15
0
    def check_joined_config(self, client_num, upload_dircap):
        """Tests that our collective directory has the readonly cap of
        our upload directory.
        """
        action = start_action(action_type=u"check-joined-config")
        with action.context():
            collective_readonly_cap = self.get_caps_from_files(client_num)[0]
            d = DeferredContext(
                self.do_cli(
                    "ls",
                    "--json",
                    collective_readonly_cap,
                    client_num=client_num,
                ))

        def _done(args):
            (rc, stdout, stderr) = args
            self.assertEqual(rc, 0)
            return (rc, stdout, stderr)

        d.addCallback(_done)

        def test_joined_magic_folder(args):
            (rc, stdout, stderr) = args
            readonly_cap = unicode(
                uri.from_string(upload_dircap).get_readonly().to_string(),
                'utf-8')
            s = re.search(readonly_cap, stdout)
            self.assertTrue(s is not None)
            return None

        d.addCallback(test_joined_magic_folder)
        return d.addActionFinish()
Beispiel #16
0
    def do_join(self, client_num, local_dir, invite_code):
        action = start_action(
            action_type=u"join-magic-folder",
            client_num=client_num,
            local_dir=local_dir,
            invite_code=invite_code,
        )
        with action.context():
            precondition(isinstance(local_dir, unicode), local_dir=local_dir)
            precondition(isinstance(invite_code, str), invite_code=invite_code)
            local_dir_arg = unicode_to_argv(local_dir)
            d = DeferredContext(
                self.do_cli(
                    "magic-folder",
                    "join",
                    "--author",
                    "test-dummy",
                    invite_code,
                    local_dir_arg,
                    client_num=client_num,
                ))

        def _done(args):
            (rc, stdout, stderr) = args
            self.assertEqual(rc, 0)
            self.assertEqual(stdout, "")
            self.assertEqual(stderr, "")
            return (rc, stdout, stderr)

        d.addCallback(_done)
        return d.addActionFinish()
Beispiel #17
0
def create_user_bucket(reactor, client, bucketname):
    """
    Create an S3 bucket for a user's grid.

    If S3 errors are encountered, retries will be attempted.  If too
    many errors are encountered, this will give up and return a
    failure.

    @param reactor: An IReactorTime which can be used to schedule retries.
    @param client: A txaws.s3.client.S3Client which can be used to create the bucket.
    @param bucketname: The name of the S3 bucket to create.

    @return: A Deferred that fires when the bucket has been created or
        fails when too many errors are encountered.
    """
    action = startAction(
        action_type=u"initialize:create_user_bucket",
        name=bucketname,
    )
    with action.context():
        d = DeferredContext(
            retry_failure(
                reactor,
                lambda: client.create_bucket(bucketname),
                expected=[S3Error],
                steps=backoff(),
            ),
        )
        return d.addActionFinish()
Beispiel #18
0
def run_state_change(change, deployer):
    """
    Apply the change to local state.

    :param change: Either an ``IStateChange`` provider or the result of an
        ``in_parallel`` or ``sequentially`` call.
    :param IDeployer deployer: The ``IDeployer`` to use.  Specific
        ``IStateChange`` providers may require specific ``IDeployer`` providers
        that provide relevant functionality for applying the change.

    :return: ``Deferred`` firing when the change is done.
    """
    if isinstance(change, _InParallel):
        return gather_deferreds(
            list(
                run_state_change(subchange, deployer)
                for subchange in change.changes))
    if isinstance(change, _Sequentially):
        d = succeed(None)
        for subchange in change.changes:
            d.addCallback(lambda _, subchange=subchange: run_state_change(
                subchange, deployer))
        return d

    with change.eliot_action.context():
        context = DeferredContext(maybeDeferred(change.run, deployer))
        context.addActionFinish()
        return context.result
Beispiel #19
0
    def _update_connection(self, connection, configuration, state):
        """
        Send a ``ClusterStatusCommand`` to an agent.

        :param ControlAMP connection: The connection to use to send the
            command.

        :param Deployment configuration: The cluster configuration to send.
        :param DeploymentState state: The current cluster state to send.
        """
        action = LOG_SEND_TO_AGENT(agent=connection)
        with action.context():
            # Use ``maybeDeferred`` so if an exception happens,
            # it will be wrapped in a ``Failure`` - see FLOC-3221
            d = DeferredContext(
                maybeDeferred(connection.callRemote,
                              ClusterStatusCommand,
                              configuration=configuration,
                              state=state,
                              eliot_context=action))
            d.addActionFinish()
            d.result.addErrback(lambda _: None)

        update = self._current_command[connection] = _UpdateState(
            response=d.result,
            next_scheduled=False,
        )

        def finished_update(ignored):
            del self._current_command[connection]

        update.response.addCallback(finished_update)
Beispiel #20
0
    def from_url(cls, reactor, url, key, alg=jose.RS256, jws_client=None):
        """
        Construct a client from an ACME directory at a given URL.

        :param url: The ``twisted.python.url.URL`` to fetch the directory from.
            See `txacme.urls` for constants for various well-known public
            directories.
        :param reactor: The Twisted reactor to use.
        :param ~acme.jose.jwk.JWK key: The client key to use.
        :param alg: The signing algorithm to use.  Needs to be compatible with
            the type of key used.
        :param JWSClient jws_client: The underlying client to use, or ``None``
            to construct one.

        :return: The constructed client.
        :rtype: Deferred[`Client`]
        """
        action = LOG_ACME_CONSUME_DIRECTORY(
            url=url, key_type=key.typ, alg=alg.name)
        with action.context():
            check_directory_url_type(url)
            jws_client = _default_client(jws_client, reactor, key, alg)
            return (
                DeferredContext(jws_client.get(url.asText()))
                .addCallback(json_content)
                .addCallback(messages.Directory.from_json)
                .addCallback(
                    tap(lambda d: action.add_success_fields(directory=d)))
                .addCallback(cls, reactor, key, jws_client)
                .addActionFinish())
Beispiel #21
0
    def output_CONVERGE(self, context):
        known_local_state = self.cluster_state.get_node(self.deployer.hostname)
        d = DeferredContext(self.deployer.discover_state(known_local_state))

        def got_local_state(state_changes):
            # Current cluster state is likely out of date as regards the local
            # state, so update it accordingly.
            for state in state_changes:
                self.cluster_state = state.update_cluster_state(
                    self.cluster_state)
            with LOG_SEND_TO_CONTROL_SERVICE(
                    self.fsm.logger, connection=self.client) as context:
                self.client.callRemote(NodeStateCommand,
                                       state_changes=state_changes,
                                       eliot_context=context)
            action = self.deployer.calculate_changes(self.configuration,
                                                     self.cluster_state)
            return action.run(self.deployer)

        d.addCallback(got_local_state)

        # It would be better to have a "quiet time" state in the FSM and
        # transition to that next, then have a timeout input kick the machine
        # back around to the beginning of the loop in the FSM.  However, we're
        # not going to keep this sleep-for-a-bit solution in the long term.
        # Instead, we'll be more event driven.  So just going with the simple
        # solution and inserting a side-effect-y delay directly here.

        d.addCallback(lambda _: self.reactor.callLater(
            1.0, self.fsm.receive, ConvergenceLoopInputs.ITERATION_DONE))
Beispiel #22
0
    def update_registration(self, regr, uri=None):
        """
        Submit a registration to the server to update it.

        :param ~acme.messages.RegistrationResource regr: The registration to
            update.  Can be a :class:`~acme.messages.NewRegistration` instead,
            in order to create a new registration.
        :param str uri: The url to submit to.  Must be
            specified if a :class:`~acme.messages.NewRegistration` is provided.

        :return: The updated registration resource.
        :rtype: Deferred[`~acme.messages.RegistrationResource`]
        """
        if uri is None:
            uri = regr.uri
        if isinstance(regr, messages.RegistrationResource):
            message = messages.UpdateRegistration(**dict(regr.body))
        else:
            message = regr
        action = LOG_ACME_UPDATE_REGISTRATION(uri=uri, registration=message)
        with action.context():
            return (
                DeferredContext(self._client.post(uri, message))
                .addCallback(self._parse_regr_response, uri=uri)
                .addCallback(self._check_regr, regr)
                .addCallback(
                    tap(lambda r: action.add_success_fields(registration=r)))
                .addActionFinish())
Beispiel #23
0
    def _send_state_to_control_service(self, state_changes):
        context = LOG_SEND_TO_CONTROL_SERVICE(
            self.fsm.logger,
            connection=self.client,
            local_changes=list(state_changes),
        )
        with context.context():
            d = DeferredContext(
                self.client.callRemote(NodeStateCommand,
                                       state_changes=state_changes,
                                       eliot_context=context))

            def record_acknowledged_state(ignored):
                self._last_acknowledged_state = state_changes

            def clear_acknowledged_state(failure):
                # We don't know if the control service has processed the update
                # or not. So we clear the last acknowledged state so that we
                # always send the state on the next iteration.
                self._last_acknowledged_state = None
                return failure

            d.addCallbacks(record_acknowledged_state, clear_acknowledged_state)
            d.addErrback(writeFailure, self.fsm.logger,
                         u"Failed to send local state to control node.")
            return d.addActionFinish()
Beispiel #24
0
 def poll(self, authzr):
     """
     Update an authorization from the server (usually to check its status).
     """
     action = LOG_ACME_POLL_AUTHORIZATION(authorization=authzr)
     with action.context():
         return (
             DeferredContext(self._client.get(authzr.uri))
             # Spec says we should get 202 while pending, Boulder actually
             # sends us 200 always, so just don't check.
             # .addCallback(self._expect_response, http.ACCEPTED)
             .addCallback(
                 lambda res:
                 self._parse_authorization(res, uri=authzr.uri)
                 .addCallback(
                     self._check_authorization, authzr.body.identifier)
                 .addCallback(
                     lambda authzr:
                     (authzr,
                      self.retry_after(res, _now=self._clock.seconds)))
             )
             .addCallback(tap(
                 lambda a_r: action.add_success_fields(
                     authorization=a_r[0], retry_after=a_r[1])))
             .addActionFinish())
Beispiel #25
0
def logged_run_process(reactor, command):
    """
    Run a child process, and log the output as we get it.

    :param reactor: An ``IReactorProcess`` to spawn the process on.
    :param command: An argument list specifying the child process to run.

    :return: A ``Deferred`` that calls back with ``_ProcessResult`` if the
        process exited successfully, or errbacks with
        ``_CalledProcessError`` otherwise.
    """
    d = Deferred()
    action = TWISTED_CHILD_PROCESS_ACTION(command=command)
    with action.context():
        d2 = DeferredContext(d)
        protocol = _LoggingProcessProtocol(d, action)
        reactor.spawnProcess(protocol, command[0], command)

        def process_ended((reason, output)):
            status = reason.value.status
            if status:
                raise _CalledProcessError(returncode=status,
                                          cmd=command,
                                          output=output)
            return _ProcessResult(
                command=command,
                status=status,
                output=output,
            )

        d2.addCallback(process_ended)
        d2.addActionFinish()
        return d2.result
Beispiel #26
0
    def request_issuance(self, csr):
        """
        Request a certificate.

        Authorizations should have already been completed for all of the names
        requested in the CSR.

        Note that unlike `acme.client.Client.request_issuance`, the certificate
        resource will have the body data as raw bytes.

        ..  seealso:: `txacme.util.csr_for_names`

        ..  todo:: Delayed issuance is not currently supported, the server must
                   issue the requested certificate immediately.

        :param csr: A certificate request message: normally
            `txacme.messages.CertificateRequest` or
            `acme.messages.CertificateRequest`.

        :rtype: Deferred[`acme.messages.CertificateResource`]
        :return: The issued certificate.
        """
        action = LOG_ACME_REQUEST_CERTIFICATE()
        with action.context():
            return (
                DeferredContext(
                    self._client.post(
                        self.directory[csr], csr,
                        content_type=DER_CONTENT_TYPE,
                        headers=Headers({b'Accept': [DER_CONTENT_TYPE]})))
                .addCallback(self._expect_response, http.CREATED)
                .addCallback(self._parse_certificate)
                .addActionFinish())
def converge(config, subscriptions, k8s, aws):
    """
    Bring provisioned resources in line with active subscriptions.

    :param DeploymentConfig config: S4-global configuration necessary for
        provisioning resources.

    :param subscription_manager.Client subscription_manager: A client for
        interrogating the subscriptions database.

    :param txkube.IKubernetesClient k8s: A client for interacting with
        Kubernetes.

    :param AWSServiceRegion aws: A client for interacting with AWS.

    :return Deferred(NoneType): The returned ``Deferred`` fires after one
        attempt has been made to bring the actual state of provisioned
        resources in line with the desired state of provisioned resources
        based on the currently active subscriptions.
    """
    # Create and destroy deployments as necessary.  Use the
    # subscription manager to find out what subscriptions are active
    # and use look at the Kubernetes configuration to find out what
    # subscription-derived deployments exist.  Also detect port
    # mis-configurations and correct them.
    a = start_action(action_type=u"converge")
    with a.context():
        d = DeferredContext(_get_converge_inputs(config, subscriptions, k8s, aws))
        d.addCallback(_converge_logic, config, subscriptions, k8s, aws)
        d.addCallback(_execute_converge_outputs)
        d.addCallback(lambda result: None)
        return d.addActionFinish()
Beispiel #28
0
    def fetch_chain(self, certr, max_length=10):
        """
        Fetch the intermediary chain for a certificate.

        :param acme.messages.CertificateResource certr: The certificate to
            fetch the chain for.
        :param int max_length: The maximum length of the chain that will be
            fetched.

        :rtype: Deferred[List[`acme.messages.CertificateResource`]]
        :return: The issuer certificate chain, ordered with the trust anchor
                 last.
        """
        action = LOG_ACME_FETCH_CHAIN()
        with action.context():
            if certr.cert_chain_uri is None:
                return succeed([])
            elif max_length < 1:
                raise errors.ClientError('chain too long')
            return (
                DeferredContext(
                    self._client.get(
                        certr.cert_chain_uri,
                        content_type=DER_CONTENT_TYPE,
                        headers=Headers({b'Accept': [DER_CONTENT_TYPE]})))
                .addCallback(self._parse_certificate)
                .addCallback(
                    lambda issuer:
                    self.fetch_chain(issuer, max_length=max_length - 1)
                    .addCallback(lambda chain: [issuer] + chain))
                .addActionFinish())
Beispiel #29
0
        def api_clean_state(
            name,
            configuration_method,
            state_method,
            delete_method,
        ):
            """
            Clean entities from the cluster.

            :param unicode name: The name of the entities to clean.
            :param configuration_method: The function to obtain the configured
                entities.
            :param state_method: The function to get the current entities.
            :param delete_method: The method to delete an entity.

            :return: A `Deferred` that fires when the entities have been
                deleted.
            """
            context = start_action(action_type=u"acceptance:cleanup_" + name, )
            with context.context():
                get_items = DeferredContext(configuration_method())

                def delete_items(items):
                    return gather_deferreds(
                        list(delete_method(item) for item in items))

                get_items.addCallback(delete_items)
                get_items.addCallback(lambda ignored: loop_until(
                    reactor, lambda: state_method().addCallback(lambda result:
                                                                [] == result)))
                return get_items.addActionFinish()
Beispiel #30
0
    def _post(self, url, obj, content_type, **kwargs):
        """
        POST an object and check the response.

        :param str url: The URL to request.
        :param ~acme.jose.interfaces.JSONDeSerializable obj: The serializable
            payload of the request.
        :param bytes content_type: The expected content type of the response.

        :raises txacme.client.ServerError: If server response body carries HTTP
            Problem (draft-ietf-appsawg-http-problem-00).
        :raises acme.errors.ClientError: In case of other protocol errors.
        """
        with LOG_JWS_POST().context():
            headers = kwargs.setdefault('headers', Headers())
            headers.setRawHeaders(b'content-type', [JSON_CONTENT_TYPE])
            return (
                DeferredContext(self._get_nonce(url))
                .addCallback(self._wrap_in_jws, obj)
                .addCallback(
                    lambda data: self._send_request(
                        u'POST', url, data=data, **kwargs))
                .addCallback(self._add_nonce)
                .addCallback(self._check_response, content_type=content_type)
                .addActionFinish())