コード例 #1
0
 def _initialise_client(self):
     """
     Initialise flocker client.
     """
     self.client = FlockerClient(
         self.reactor,
         self.control_node_address,
         REST_API_PORT,
         self.cluster_cert,
         self.user_cert,
         self.user_key
     )
コード例 #2
0
    def from_options(cls, reactor, options):
        """
        Create a cluster container deployment object from the
        options given through command line.

        :param reactor: reactor
        :param options: ``ContainerOptions`` container the parsed
            options given to the script.
        """
        try:
            image = DockerImage(repository=options['image'])
            max_size = int(GiB(options['max-size']).to_Byte().value)
            mountpoint = unicode(options['mountpoint'])
            control_node_address = options['control-node']
            timeout = options['wait']
        except Exception as e:
            sys.stderr.write("%s: %s\n" % ("Missing or wrong arguments", e))
            sys.stderr.write(e.args[0])
            sys.stderr.write('\n\n')
            sys.stderr.write(options.getSynopsis())
            sys.stderr.write('\n')
            sys.stderr.write(options.getUsage())
            raise SystemExit(1)

        certificates_path = FilePath(options['cert-directory'])
        cluster_cert = certificates_path.child(b"cluster.crt")
        user_cert = certificates_path.child(b"user.crt")
        user_key = certificates_path.child(b"user.key")

        # Initialise client
        client = FlockerClient(reactor, control_node_address, REST_API_PORT,
                               cluster_cert, user_cert, user_key)

        return cls(reactor, image, max_size, mountpoint, control_node_address,
                   timeout, cluster_cert, user_cert, user_key, client)
コード例 #3
0
def make_client(reactor, cluster):
    """
    Create a :class:`FlockerClient` object for accessing the given cluster.

    :param reactor: The reactor.
    :param flocker.provision._common.Cluster cluster: The target cluster.
    :return: The client object.
    :rtype: flocker.apiclient.FlockerClient
    """
    control_node = cluster.control_node.address
    certificates_path = cluster.certificates_path
    cluster_cert = certificates_path.child(b"cluster.crt")
    user_cert = certificates_path.child(b"user.crt")
    user_key = certificates_path.child(b"user.key")
    return FlockerClient(reactor, control_node, REST_API_PORT, cluster_cert,
                         user_cert, user_key)
コード例 #4
0
ファイル: cluster_cleanup.py プロジェクト: zendad/flocker
def main(reactor, args):
    try:
        options = ScriptOptions()
        options.parseOptions(args)
    except UsageError as e:
        sys.stderr.write(e.args[0])
        sys.stderr.write('\n\n')
        sys.stderr.write(options.getSynopsis())
        sys.stderr.write('\n')
        sys.stderr.write(options.getUsage())
        raise SystemExit(1)

    certificates_path = FilePath(options['cert-directory'])
    cluster_cert = certificates_path.child(b"cluster.crt")
    user_cert = certificates_path.child(b"user.crt")
    user_key = certificates_path.child(b"user.key")
    client = FlockerClient(reactor, options['control-node'], REST_API_PORT,
                           cluster_cert, user_cert, user_key)
    return cleanup_cluster(client, options['wait'])
コード例 #5
0
class ClusterContainerDeployment(object):
    """
    Class that contains all the methods needed to deploy a new config in a
    cluster.

    :ivar options: ``ContainerOptions`` with the options passed to the script
    :ivar application_template: template of the containers to deploy.
    :ivar per_node: number of containers and dataset per node.
    :ivar control_node_address: public ip address of the control node.
    :ivar cluster_cert: ``FilePath`` of the cluster certificate.
    :ivar user_cert: ``FilePath`` of the user certificate.
    :ivar user_key: ``FilePath`` of the user key.
    :ivar client: ``FlockerClient`` conected to the cluster.
    :ivar reactor: ``Reactor`` used by the client.
    :ivar nodes: list of `Node` returned by client.list_nodes
    """
    def __init__(self, reactor, env, options):
        """
        ``ClusterContainerDeployment`` constructor.

        :param reactor: ``Reactor`` we are using.
        :param env: ``environ`` with the current environment.
            NOTE: alternative of making it work with env variables pending
            implementation
        :param options: ``ContainerOptions`` with the options passed to the
            the script.
        """
        self.options = options
        try:
            self.application_template = self.options['template']
            self.per_node = self.options['apps-per-node']
            self.control_node_address = self.options['control-node']
            self.timeout = self.options['wait']
            if self.timeout is None:
                # Wait two hours by default
                self.timeout = 72000
        except Exception as e:
            sys.stderr.write("%s: %s\n" % ("Missing or wrong arguments", e))
            sys.stderr.write(e.args[0])
            sys.stderr.write('\n\n')
            sys.stderr.write(options.getSynopsis())
            sys.stderr.write('\n')
            sys.stderr.write(options.getUsage())
            raise SystemExit(1)

        certificates_path = FilePath(self.options['cert-directory'])
        self.cluster_cert = certificates_path.child(b"cluster.crt")
        self.user_cert = certificates_path.child(b"user.crt")
        self.user_key = certificates_path.child(b"user.key")
        self.client = None
        self.reactor = reactor
        self.nodes = []
        self._initialise_client()

    def _initialise_client(self):
        """
        Initialise flocker client.
        """
        self.client = FlockerClient(
            self.reactor,
            self.control_node_address,
            REST_API_PORT,
            self.cluster_cert,
            self.user_cert,
            self.user_key
        )

    def _set_nodes(self, nodes):
        """
        Set the list of the nodes in the cluster.
        """
        self.nodes = nodes

    def deploy(self):
        """
        Deploy the new configuration: create the requested containers
        and dataset in the cluster nodes.

        :return Deferred: that will fire once the request to create all
            the containers and datasets has been sent.
        """
        Message.log(action="Listing current nodes")
        d = self.client.list_nodes()
        d.addCallback(self._set_nodes)
        d.addCallback(self._build_config)
        d.addCallback(self._configure)
        return d

    def is_datasets_deployment_complete(self):
        """
        Check if all the dataset have been created.

        :return Deferred: that will fire once the list datasets call
            has been completed, and which result will bee True if all the
            dataset have been created, or false otherwise.
        """
        number_of_datasets = self.per_node * len(self.nodes)

        d = self.client.list_datasets_state()

        def do_we_have_enough_datasets(datasets):
            msg = (
                "Waiting for the datasets to be ready..."
                "Created {current_datasets} of {total_datasets}"

            ).format(
                current_datasets=len(datasets),
                total_datasets=number_of_datasets,
            )
            Message.log(action=msg)

            return (len(datasets) >= number_of_datasets)

        d.addCallback(do_we_have_enough_datasets)
        return d

    def is_container_deployment_complete(self):
        """
        Check if all the containers have been created.

        :return Deferred: that will fire once the list containers call
            has been completed, and which result will bee True if all the
            containers have been created, or False otherwise.
        """
        number_of_containers = self.per_node * len(self.nodes)

        d = self.client.list_containers_state()

        def do_we_have_enough_containers(containers):
            msg = (
                "Waiting for the containers to be ready..."
                "Created {current_containers} of {total_containers}"

            ).format(
                current_containers=len(containers),
                total_containers=number_of_containers,
            )
            Message.log(action=msg)
            return (len(containers) >= number_of_containers)

        d.addCallback(do_we_have_enough_containers)
        return d

    @inlineCallbacks
    def deploy_and_wait_for_creation(self):
        """
        Function that will deploy the new configuration (create all the
        dataset and container requested) and will only return once all
        of them have been created.
        """
        yield self.deploy()
        yield loop_until(self.reactor,
                         self.is_datasets_deployment_complete,
                         repeat(1, self.timeout))
        yield loop_until(self.reactor,
                         self.is_container_deployment_complete,
                         repeat(1, self.timeout))

    def _build_config(self, ignored):
        """
        Build a Flocker deployment configuration for the given cluster
        and parameters.
        The configuration consists of identically configured applications
        (containers) uniformly spread over all cluster nodes.

        :return dict: containing the json we need to send to compose to
            create the datasets and containers we want.
        """
        Message.log(action="Building config")
        application_root = {}
        applications = {}
        application_root["version"] = 1
        application_root["applications"] = applications
        for node in self.nodes:
            for i in range(self.per_node):
                name = "app_%s_%d" % (node.public_address, i)
                applications[name] = deepcopy(self.application_template)

        deployment_root = {}
        nodes = {}
        deployment_root["nodes"] = nodes
        deployment_root["version"] = 1
        for node in self.nodes:
            addr = "%s" % node.public_address
            nodes[addr] = []
            for i in range(self.per_node):
                name = "app_%s_%d" % (node.public_address, i)
                nodes[addr].append(name)

        return {"applications": application_root,
                "deployment": deployment_root}

    def _configure(self, configuration):
        """
        Configure the cluster with the given deployment configuration.

        :param dict configuration: dictionary with the configuration
            to deploy.
        :return Deferred: Deferred that fires when the configuration is pushed
                          to the cluster's control agent.
        """
        Message.log(action="Deploying new config")
        base_url = b"https://{}:{}/v1".format(
            self.control_node_address, REST_API_PORT
        )
        cluster_cert = self.cluster_cert
        user_cert = self.user_cert
        user_key = self.user_key
        body = dumps(configuration)
        treq_client = treq_with_authentication(
            self.reactor, cluster_cert, user_cert, user_key)

        def do_configure():
            posted = treq_client.post(
                base_url + b"/configuration/_compose", data=body,
                headers={b"content-type": b"application/json"},
                persistent=False
            )

            def got_response(response):
                if response.code != OK:
                    d = json_content(response)

                    def got_error(error):
                        if isinstance(error, dict):
                            error = error[u"description"] + u"\n"
                        else:
                            error = u"Unknown error: " + unicode(error) + "\n"
                        raise ResponseError(response.code, error)

                    d.addCallback(got_error)
                    return d

            posted.addCallback(got_response)
            return posted

        return do_configure()
コード例 #6
0
    def from_options(cls, reactor, options):
        """
        Create a cluster container deployment object from the
        options given through command line.

        :param reactor: reactor
        :param options: ``ContainerOptions`` container the parsed
            options given to the script.
        """
        try:
            image = DockerImage(repository=options["image"])
            max_size = int(GiB(options["max-size"]).to_Byte().value)
            mountpoint = unicode(options["mountpoint"])
            per_node = options["apps-per-node"]
            control_node_address = options["control-node"]
            timeout = options["wait"]
            wait_interval = options["wait-interval"]

        except Exception as e:
            sys.stderr.write("%s: %s\n" % ("Missing or wrong arguments", e))
            sys.stderr.write(e.args[0])
            sys.stderr.write("\n\n")
            sys.stderr.write(options.getSynopsis())
            sys.stderr.write("\n")
            sys.stderr.write(options.getUsage())
            raise SystemExit(1)

        certificates_path = FilePath(options["cert-directory"])
        cluster_cert = certificates_path.child(b"cluster.crt")
        user_cert = certificates_path.child(b"user.crt")
        user_key = certificates_path.child(b"user.key")

        # Initialise client
        client = FlockerClient(reactor, control_node_address, REST_API_PORT, cluster_cert, user_cert, user_key)

        # Listing datasets and containers to know the initial number of
        # datasets and containers, so we know the total number of them
        # we are expecting to have.
        # XXX please note that, if some of those initial datasets or containers
        # are being deleted, the output of this script won't be as expected,
        # and it will end up timing out waiting for all the containers and
        # datasets to be ready. This is a possible future improvement (bear
        # it in mind if reusing the code), but it is not needed by benchmarking
        # as it is not an scenario we will have, and even if we had it, we
        # still can re-run this script to create the extra datasets and
        # containers we may need, or even cleanup the cluster and start again.

        d = gatherResults([client.list_nodes(), client.list_datasets_state(), client.list_containers_state()])

        def create_instance(result):
            nodes, datasets, containers = result

            return cls(
                reactor,
                image,
                max_size,
                mountpoint,
                per_node,
                control_node_address,
                timeout,
                wait_interval,
                cluster_cert,
                user_cert,
                user_key,
                len(datasets),
                len(containers),
                client,
                nodes,
            )

        d.addCallback(create_instance)

        return d