Beispiel #1
0
    def _get_available_system(self):
        names = yield self._caller.call(
            "find_system", ({"mgmt_classes": self._available_class,
                             "netboot_enabled": "true"},))
        if not names:
            raise ProviderError("Could not find any Cobbler systems marked as "
                                "available and configured for network boot.")

        # It's possible that some systems could be marked both available and
        # acquired, so we check each one for sanity (but only complain when
        # the problem becomes critical: ie, we can't find a system in a sane
        # state).
        inconsistent_instance_ids = []
        for name in names:
            info = yield self._caller.call("get_system", (name,))
            if info == "~":
                continue
            classes = info["mgmt_classes"]
            if self._acquired_class in classes:
                inconsistent_instance_ids.append(info["uid"])
                continue
            returnValue((info["uid"], map(self._class_swapper, classes)))
        raise ProviderError(
            "All available Cobbler systems were also marked as acquired "
            "(instances: %s)."
            % ", ".join(inconsistent_instance_ids))
Beispiel #2
0
 def shutdown_machine(self, machine):
     """Terminate the given machine"""
     if not isinstance(machine, DummyMachine):
         return fail(ProviderError("Invalid machine for provider"))
     for m in self._machines:
         if m.instance_id == machine.instance_id:
             self._machines.remove(m)
             return m
     return fail(ProviderError("Machine not found %r" % machine))
Beispiel #3
0
 def extract_name(systems):
     if len(systems) > 1:
         raise ProviderError(
             "Got multiple names for machine %s: %s"
             % (instance_id, ", ".join(systems)))
     if not systems:
         raise MachinesNotFound([instance_id])
     return systems[0]
Beispiel #4
0
 def open_port(self, machine, machine_id, port, protocol="tcp"):
     """Dummy equivalent of ec2-authorize-group"""
     if not isinstance(machine, DummyMachine):
         return fail(ProviderError("Invalid machine for provider"))
     machine._opened_ports.add((port, protocol))
     log.debug("Opened %s/%s on provider machine %r", port, protocol,
               machine.instance_id)
     return succeed(None)
Beispiel #5
0
def _convert_error(failure, method, url, errors):
    if failure.check(Error):
        status = failure.value.status
        error = errors.get(int(status))
        if error:
            raise error
        raise ProviderError("Unexpected HTTP %s trying to %s %s" %
                            (status, method, url))
    return convert_unknown_error(failure)
Beispiel #6
0
    def get_opened_ports(self, machine, machine_id):
        """Dummy equivalent of ec2-describe-group

        This returns the current exposed ports in the environment for
        this machine. This directly goes against the provider. For
        EC2, this would be eventually consistent.
        """
        if not isinstance(machine, DummyMachine):
            return fail(ProviderError("Invalid machine for provider"))
        return succeed(machine._opened_ports)
Beispiel #7
0
    def start_machine(self, machine_data, master=False):
        """Start a machine in the provider.

        @param machine_data: a dictionary of data to pass along to the newly
           launched machine.

        @param master: if True, machine will initialize the juju admin
            and run a provisioning agent.
        """
        return fail(ProviderError("Only local machine available"))
Beispiel #8
0
 def start_machine(self, machine_data, master=False):
     """Start a machine in the provider."""
     if not "machine-id" in machine_data:
         return fail(
             ProviderError(
                 "Machine state `machine-id` required in machine_data"))
     dns_name = machine_data.get("dns-name")
     machine = DummyMachine(len(self._machines), dns_name)
     self._machines.append(machine)
     return succeed([machine])
Beispiel #9
0
def _parse_auth_info(auth_info):
    method, info_str = auth_info.split(' ', 1)
    if method != "Digest":
        raise ProviderError("Unknown authentication method: %s" % method)
    items = parse_http_list(info_str)
    info = parse_keqv_list(items)

    try:
        qop = info["qop"]
        realm = info["realm"]
        nonce = info["nonce"]
    except KeyError as e:
        raise ProviderError("Authentication request missing required key: %s" %
                            e)
    algorithm = info.get("algorithm", "MD5")
    if algorithm != "MD5":
        raise ProviderError("Unsupported digest algorithm: %s" % algorithm)
    if "auth" not in qop.split(","):
        raise ProviderError("Unsupported quality-of-protection: %s" % qop)
    return realm, nonce, "auth", algorithm
Beispiel #10
0
 def close_port(self, machine, machine_id, port, protocol="tcp"):
     """Dummy equivalent of ec2-revoke-group"""
     if not isinstance(machine, DummyMachine):
         return fail(ProviderError("Invalid machine for provider"))
     try:
         machine._opened_ports.remove((port, protocol))
         log.debug("Closed %s/%s on provider machine %r", port, protocol,
                   machine.instance_id)
     except KeyError:
         pass
     return succeed(None)
Beispiel #11
0
 def get_file_storage(self):
     """Retrieve the provider C{FileStorage} abstraction.
     """
     storage_path = self.config.get(
         "storage-dir", os.path.join(self._directory, "files"))
     if not os.path.exists(storage_path):
         try:
             os.makedirs(storage_path)
         except OSError:
             raise ProviderError(
                 "Unable to create file storage for environment")
     return LocalStorage(storage_path)
Beispiel #12
0
    def get_machines(self, instance_ids=()):
        """List machines running in the provider.

        @param instance_ids: ids of instances you want to get. Leave blank
            to list all machines owned by juju.

        @return: a list of LocalMachine, always contains one item.

        @raise: MachinesNotFound
        """
        if instance_ids and instance_ids != ["local"]:
            raise ProviderError("Only local machine available")
        return succeed([LocalMachine()])
Beispiel #13
0
    def start_machine(self, machine_data, master=False):
        """Start an EC2 machine.

        :param dict machine_data: desired characteristics of the new machine;
            it must include a "machine-id" key, and may include a "constraints"
            key to specify the underlying OS and hardware.

        :param bool master: if True, machine will initialize the juju admin
            and run a provisioning agent, in addition to running a machine
            agent.
        """
        if "machine-id" not in machine_data:
            return fail(ProviderError(
                "Cannot launch a machine without specifying a machine-id"))
        machine_id = machine_data["machine-id"]
        constraints = machine_data.get("constraints", {})
        return EC2LaunchMachine(self, master, constraints).run(machine_id)
Beispiel #14
0
    def get_url(self, key):
        """Get a network url to a local provider storage.

        The command line tools directly utilize the disk backed
        storage. The agents will use the read only web interface
        provided by the StorageServer to download resources, as
        in the local provider scenario they won't always have
        direct disk access.
        """
        try:
            storage_data = (yield self.get(SERVER_URL_KEY)).read()
        except FileNotFound:
            storage_data = ""

        if not storage_data or not "storage-url" in storage_data:
            raise ProviderError("Storage not initialized")
        url = yaml.load(storage_data)["storage-url"]
        returnValue(url + key)
Beispiel #15
0
    def put(self, name, file_object):
        """Upload a file to WebDAV.

        :param unicode remote_path: path on which to store the content

        :param file_object: open file object containing the content

        :rtype: :class:`twisted.internet.defer.Deferred`
        """
        url = self.get_url(name)
        postdata = file_object.read()
        d = get_page_auth(url, self._auth, method="PUT", postdata=postdata)
        d.addCallback(lambda _: True)
        d.addErrback(
            _convert_error, "PUT", url, {
                401:
                ProviderError(
                    "The supplied storage credentials were not accepted by the "
                    "server")
            })
        return d
Beispiel #16
0
    def shutdown_machines(self, machines):
        """Terminate machines associated with this provider.

        :param machines: machines to shut down
        :type machines: list of
            :class:`juju.providers.ec2.machine.EC2ProviderMachine`

        :return: list of terminated
            :class:`juju.providers.ec2.machine.EC2ProviderMachine`
            instances
        :rtype: :class:`twisted.internet.defer.Deferred`
        """
        if not machines:
            returnValue([])

        for machine in machines:
            if not isinstance(machine, EC2ProviderMachine):
                raise ProviderError("Can only shut down EC2ProviderMachines; "
                                    "got a %r" % type(machine))

        ids = [m.instance_id for m in machines]
        killable_machines = yield self.get_machines(ids)
        if not killable_machines:
            returnValue([])  # Nothing to do

        killable_ids = [m.instance_id for m in killable_machines]
        terminated = yield self.ec2.terminate_instances(*killable_ids)

        # Pass on what was actually terminated, in the case the
        # machine has somehow disappeared since get_machines
        # above. This is to avoid getting EC2Error: Error Message:
        # Invalid id when running ec2.describe_instances in
        # remove_security_groups
        terminated_ids = [info[0] for info in terminated]
        yield remove_security_groups(self, terminated_ids)
        returnValue(killable_machines)
Beispiel #17
0
 def _cannot_write(self, failure):
     raise ProviderError(
         "Bootstrap aborted because file storage is not writable: %s" %
         str(failure.value))
Beispiel #18
0
 def shutdown_machine(self, machine_id):
     return fail(ProviderError(
         "Not enabled for local dev, use remove-unit"))
Beispiel #19
0
 def get_placement_policy(self):
     """Local dev supports only one unit placement policy."""
     if self.config.get("placement", LOCAL_POLICY) != LOCAL_POLICY:
         raise ProviderError(
             "Unsupported placement policy for local provider")
     return LOCAL_POLICY
Beispiel #20
0
    def bootstrap(self):
        """Bootstrap a local development environment.
        """
        # Check for existing environment
        state = yield self.load_state()
        if state is not False:
            raise ProviderError("Environment already bootstrapped")

        # Check for required packages
        log.info("Checking for required packages...")
        missing = check_packages(*REQUIRED_PACKAGES)
        if missing:
            raise ProviderError("Missing packages %s" % (
                ", ".join(sorted(list(missing)))))

        # Get/create directory for zookeeper and files
        zookeeper_dir = os.path.join(self._directory, "zookeeper")
        if not os.path.exists(zookeeper_dir):
            os.makedirs(zookeeper_dir)

        # Start networking, and get an open port.
        log.info("Starting networking...")
        net = Network("default", subnet=122)

        # Start is a noop if its already started, which it is by default,
        # per libvirt-bin package installation
        yield net.start()
        net_attributes = yield net.get_attributes()
        port = get_open_port(net_attributes["ip"]["address"])

        # Start zookeeper
        log.info("Starting zookeeper...")
        # Run zookeeper as the current user, unless we're being run as root
        # in which case run zookeeper as the 'zookeeper' user.
        zookeeper_user = None
        if os.geteuid() == 0:
            zookeeper_user = "******"
        zookeeper = Zookeeper(zookeeper_dir,
                              port=port,
                              host=net_attributes["ip"]["address"],
                              user=zookeeper_user, group=zookeeper_user)

        yield zookeeper.start()

        # Starting provider storage server
        log.info("Starting storage server...")
        storage_server = StorageServer(
            pid_file=os.path.join(self._directory, "storage-server.pid"),
            storage_dir=os.path.join(self._directory, "files"),
            host=net_attributes["ip"]["address"],
            port=get_open_port(net_attributes["ip"]["address"]),
            log_file=os.path.join(self._directory, "storage-server.log"))
        yield storage_server.start()

        # Save the zookeeper start to provider storage.
        yield self.save_state({"zookeeper-instances": ["local"],
                               "zookeeper-address": zookeeper.address})

        # Initialize the zookeeper state
        log.debug("Initializing state...")
        admin_identity = make_identity(
            "admin:%s" % self.config["admin-secret"])
        client = ZookeeperClient(zookeeper.address)
        yield client.connect()
        hierarchy = StateHierarchy(client, admin_identity, "local", "local")
        yield hierarchy.initialize()

        # Store user credentials from the running user
        try:
            public_key = get_user_authorized_keys(self.config)
            public_key = public_key.strip()
        except LookupError, e:
            raise ProviderError(str(e))
Beispiel #21
0
 def check(actual):
     if actual != expect:
         raise ProviderError(
             "Bad result from call to %s with %s: got %r, expected %r"
             % (name, args, actual, expect))
     return actual
Beispiel #22
0
 def bad_credentials(failure):
     failure.trap(Fault)
     if "login failed" not in failure.getErrorMessage():
         return failure
     raise ProviderError("Cobbler server rejected credentials.")
Beispiel #23
0
 def test_ProviderError(self):
     error = ProviderError("Invalid credentials")
     self.assertIsJujuError(error)