예제 #1
0
def agent_add_software(agent_id):
    agent = Agent.query.filter_by(id=agent_id).first()
    if not agent:
        return (render_template(
                    "pyfarm/error.html", error="Agent %s not found" % agent_id),
                NOT_FOUND)

    software = Software.query.filter_by(id=int(request.form["software"])).first()
    if not software:
        return (render_template(
                    "pyfarm/error.html", error="Software %s not found" %
                    request.form["software"]), NOT_FOUND)

    if request.form["version"].strip() == "":
        return (render_template(
            "pyfarm/error.html", error="No version selected"), BAD_REQUEST)
    version = SoftwareVersion.query.filter_by(
        id=int(request.form["version"]), software=software).first()
    if not version:
         return (render_template(
                    "pyfarm/error.html", error="Software version %s not found" %
                    request.form["version"]), NOT_FOUND)

    agent.software_versions.append(version)
    db.session.add(agent)
    db.session.add(version)
    db.session.commit()

    assign_tasks_to_agent.delay(agent.id)

    flash("Software %s %s has been added to agent %s" %
          (software.software, version.version, agent.hostname))

    return redirect(url_for("single_agent_ui", agent_id=agent.id), SEE_OTHER)
예제 #2
0
    def post(self, agent_id):
        """
        Update an agent's columns with new information by merging the provided
        data with the agent's current definition in the database.

        .. http:post:: /api/v1/agents/(str:agent_id) HTTP/1.1

            **Request**

            .. sourcecode:: http

                POST /api/v1/agents/29d466a5-34f8-408a-b613-e6c2715077a0 HTTP/1.1
                Accept: application/json

                {"ram": 1234}


            **Response**

            .. sourcecode:: http

                HTTP/1.1 200 OK
                Content-Type: application/json

                {
                    "cpu_allocation": 1.0,
                    "cpus": 14,
                    "use_address": 311,
                    "free_ram": 133,
                    "time_offset": 0,
                    "hostname": "agent1",
                    "id": "29d466a5-34f8-408a-b613-e6c2715077a0",
                    "ip": "10.196.200.115",
                    "port": 64994,
                    "ram": 1234,
                    "ram_allocation": 0.8,
                    "state": "running",
                    "remote_ip": "10.196.200.115"
                }

        :statuscode 200:
            no error

        :statuscode 400:
            something within the request is invalid

        :statuscode 404:
            no agent could be found using the given id
        """
        agent = Agent.query.filter_by(id=agent_id).first()
        if agent is None:
            return jsonify(error="Agent %s not found" % agent_id), NOT_FOUND

        if ("remote_ip" not in g.json and
            request.headers.get("User-Agent", "") == "PyFarm/1.0 (agent)"):
            g.json["remote_ip"] = request.remote_addr

        farm_name = g.json.pop("farm_name", None)
        if farm_name and farm_name != OUR_FARM_NAME:
            return jsonify(error="Wrong farm name"), BAD_REQUEST

        current_assignments = g.json.pop("current_assignments", None)
        mac_addresses = g.json.pop("mac_addresses", None)

        # TODO return BAD_REQUEST on bad mac addresses
        if mac_addresses is not None:
            mac_addresses = [x.lower() for x in mac_addresses if MAC_RE.match(x)]

        gpus = g.json.pop("gpus", None)

        disks = g.json.pop("disks", None)

        tags = g.json.pop("tags", None)

        modified = {}

        try:
            items = g.json.iteritems
        except AttributeError:
            items = g.json.items

        state = g.json.pop("state", None)
        if state and agent.state != _AgentState.DISABLED:
            agent.state = state
            modified["state"] = state

        for key, value in items():
            if value != getattr(agent, key):
                try:
                    setattr(agent, key, value)

                # There may be something wrong with one of the fields
                # that's causing our sqlalchemy model to raise a ValueError.
                except ValueError as e:
                    return jsonify(error=str(e)), BAD_REQUEST

                modified[key] = value

        agent.last_heard_from = datetime.utcnow()

        if "upgrade_to" in modified:
            update_agent.delay(agent.id)

        if mac_addresses is not None:
            modified["mac_addresses"] = mac_addresses
            for existing_address in agent.mac_addresses:
                if existing_address.mac_address.lower() not in mac_addresses:
                    logger.debug("Existing address %s is not in supplied "
                                 "mac addresses, for agent %s, removing it.",
                                 existing_address.mac_address,
                                 agent.hostname)
                    agent.mac_addresses.remove(existing_address)
                else:
                    mac_addresses.remove(
                        existing_address.mac_address.lower())

            for new_address in mac_addresses:
                mac_address = AgentMacAddress(
                    agent=agent, mac_address=new_address)
                db.session.add(mac_address)

        if gpus is not None:
            modified["gpus"] = gpus
            for existing_gpu in agent.gpus:
                if existing_gpu.fullname not in gpus:
                    logger.debug("Existing gpu %s is not in supplied "
                                    "gpus, for agent %s, removing it.",
                                    existing_gpu.fullname,
                                    agent.hostname)
                    agent.gpus.remove(existing_gpu)
                else:
                    gpus.remove(existing_gpu.fullname)

            for gpu_name in gpus:
                gpu = GPU.query.filter_by(fullname=gpu_name).first()
                if not gpu:
                    gpu = GPU(fullname=gpu_name)
                    db.session.add(gpu)
                agent.gpus.append(gpu)

        if disks is not None:
            for old_disk in agent.disks:
                db.session.delete(old_disk)
            for disk_dict in disks:
                disk = AgentDisk(agent=agent,
                                    mountpoint=disk_dict["mountpoint"],
                                    size=disk_dict["size"],
                                    free=disk_dict["free"])
                db.session.add(disk)

        if tags is not None:
            modified["tags"] = tags
            for existing_tag in agent.tags:
                if existing_tag.tag not in tags:
                    logger.debug("Existing tag %s is not in supplied "
                                 "tags, for agent %s, removing it.",
                                 existing_tag.tag, agent.hostname)
                    agent.tags.remove(existing_tag)
                else:
                    tags.remove(existing_tag.tag)

            for tag_name in tags:
                tag = Tag.query.filter_by(tag=tag_name).first()
                if not tag:
                    tag = Tag(tag=tag_name)
                    db.session.add(tag)
                agent.tags.append(tag)

        # TODO Only do that if this is really the agent speaking to us.
        failed_tasks = []
        if (current_assignments is not None and
            agent.state != AgentState.OFFLINE):
            failed_tasks = fail_missing_assignments(agent, current_assignments)

        logger.debug(
            "Updated agent %r: %r", agent.id, modified)
        db.session.add(agent)
        db.session.commit()

        for task in failed_tasks:
            task.job.update_state()
        if agent.state == _AgentState.OFFLINE:
            for task in agent.tasks.filter(Task.state != WorkState.DONE,
                                           Task.state != WorkState.FAILED):
                task.agent = None
                task.state = None
                task.job.update_state()
                db.session.add(task)
        db.session.commit()

        assign_tasks_to_agent.delay(agent_id)

        return jsonify(agent.to_dict(unpack_relationships=["tags"])), OK
예제 #3
0
    def post(self, agent_id):
        """
        Update an agent's columns with new information by merging the provided
        data with the agent's current definition in the database.

        .. http:post:: /api/v1/agents/(str:agent_id) HTTP/1.1

            **Request**

            .. sourcecode:: http

                POST /api/v1/agents/29d466a5-34f8-408a-b613-e6c2715077a0 HTTP/1.1
                Accept: application/json

                {"ram": 1234}


            **Response**

            .. sourcecode:: http

                HTTP/1.1 200 OK
                Content-Type: application/json

                {
                    "cpu_allocation": 1.0,
                    "cpus": 14,
                    "use_address": 311,
                    "free_ram": 133,
                    "time_offset": 0,
                    "hostname": "agent1",
                    "id": "29d466a5-34f8-408a-b613-e6c2715077a0",
                    "ip": "10.196.200.115",
                    "port": 64994,
                    "ram": 1234,
                    "ram_allocation": 0.8,
                    "state": "running",
                    "remote_ip": "10.196.200.115"
                }

        :statuscode 200:
            no error

        :statuscode 400:
            something within the request is invalid

        :statuscode 404:
            no agent could be found using the given id
        """
        agent = Agent.query.filter_by(id=agent_id).first()
        if agent is None:
            return jsonify(error="Agent %s not found" % agent_id), NOT_FOUND

        if ("remote_ip" not in g.json and request.headers.get(
                "User-Agent", "") == "PyFarm/1.0 (agent)"):
            g.json["remote_ip"] = request.remote_addr

        farm_name = g.json.pop("farm_name", None)
        if farm_name and farm_name != OUR_FARM_NAME:
            return jsonify(error="Wrong farm name"), BAD_REQUEST

        current_assignments = g.json.pop("current_assignments", None)
        mac_addresses = g.json.pop("mac_addresses", None)

        # TODO return BAD_REQUEST on bad mac addresses
        if mac_addresses is not None:
            mac_addresses = [
                x.lower() for x in mac_addresses if MAC_RE.match(x)
            ]

        gpus = g.json.pop("gpus", None)

        disks = g.json.pop("disks", None)

        tags = g.json.pop("tags", None)

        modified = {}

        try:
            items = g.json.iteritems
        except AttributeError:
            items = g.json.items

        state = g.json.pop("state", None)
        if state and agent.state != _AgentState.DISABLED:
            agent.state = state
            modified["state"] = state

        for key, value in items():
            if value != getattr(agent, key):
                try:
                    setattr(agent, key, value)

                # There may be something wrong with one of the fields
                # that's causing our sqlalchemy model to raise a ValueError.
                except ValueError as e:
                    return jsonify(error=str(e)), BAD_REQUEST

                modified[key] = value

        agent.last_heard_from = datetime.utcnow()

        if "upgrade_to" in modified:
            update_agent.delay(agent.id)

        if mac_addresses is not None:
            modified["mac_addresses"] = mac_addresses
            for existing_address in agent.mac_addresses:
                if existing_address.mac_address.lower() not in mac_addresses:
                    logger.debug(
                        "Existing address %s is not in supplied "
                        "mac addresses, for agent %s, removing it.",
                        existing_address.mac_address, agent.hostname)
                    agent.mac_addresses.remove(existing_address)
                else:
                    mac_addresses.remove(existing_address.mac_address.lower())

            for new_address in mac_addresses:
                mac_address = AgentMacAddress(agent=agent,
                                              mac_address=new_address)
                db.session.add(mac_address)

        if gpus is not None:
            modified["gpus"] = gpus
            for existing_gpu in agent.gpus:
                if existing_gpu.fullname not in gpus:
                    logger.debug(
                        "Existing gpu %s is not in supplied "
                        "gpus, for agent %s, removing it.",
                        existing_gpu.fullname, agent.hostname)
                    agent.gpus.remove(existing_gpu)
                else:
                    gpus.remove(existing_gpu.fullname)

            for gpu_name in gpus:
                gpu = GPU.query.filter_by(fullname=gpu_name).first()
                if not gpu:
                    gpu = GPU(fullname=gpu_name)
                    db.session.add(gpu)
                agent.gpus.append(gpu)

        if disks is not None:
            for old_disk in agent.disks:
                db.session.delete(old_disk)
            for disk_dict in disks:
                disk = AgentDisk(agent=agent,
                                 mountpoint=disk_dict["mountpoint"],
                                 size=disk_dict["size"],
                                 free=disk_dict["free"])
                db.session.add(disk)

        if tags is not None:
            modified["tags"] = tags
            for existing_tag in agent.tags:
                if existing_tag.tag not in tags:
                    logger.debug(
                        "Existing tag %s is not in supplied "
                        "tags, for agent %s, removing it.", existing_tag.tag,
                        agent.hostname)
                    agent.tags.remove(existing_tag)
                else:
                    tags.remove(existing_tag.tag)

            for tag_name in tags:
                tag = Tag.query.filter_by(tag=tag_name).first()
                if not tag:
                    tag = Tag(tag=tag_name)
                    db.session.add(tag)
                agent.tags.append(tag)

        # TODO Only do that if this is really the agent speaking to us.
        failed_tasks = []
        if (current_assignments is not None
                and agent.state != AgentState.OFFLINE):
            failed_tasks = fail_missing_assignments(agent, current_assignments)

        logger.debug("Updated agent %r: %r", agent.id, modified)
        db.session.add(agent)
        db.session.commit()

        for task in failed_tasks:
            task.job.update_state()
        if agent.state == _AgentState.OFFLINE:
            for task in agent.tasks.filter(Task.state != WorkState.DONE,
                                           Task.state != WorkState.FAILED):
                task.agent = None
                task.state = None
                task.job.update_state()
                db.session.add(task)
        db.session.commit()

        assign_tasks_to_agent.delay(agent_id)

        return jsonify(agent.to_dict(unpack_relationships=["tags"])), OK