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)
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
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