def get(): """ **Verify your login** This function allows users to verify their login. :return: json and http status code - Example:: curl -X GET bio-portal.metacentrum.cz/api/ -H 'Cookie: cookie returned by scope' - Expected Success Response:: HTTP Status Code: 200 {"project_id": project_id, "token": token} - Expected Fail Response:: HTTP Status Code: 401 {'message': reason} """ if 'project_id' in flask_session and 'token' in flask_session: connect(flask_session["token"], flask_session["project_id"]) return {'project_id': flask_session['project_id'], 'token': flask_session['token']}, 200 return {'message': 'unauthorized'}, 401
def put(): """ **Scope to project** This function allows users to scope to their chosen project. Its json input is specified by :class:`~schema.ScopeSchema` :return: {} and http status code - Example:: curl -X PUT bio-portal.metacentrum.cz/api/ -H 'Cookie: cookie returned by login' -H 'content-type: application/json' --data '{"project_id": project_id}' - Expected Success Response:: HTTP Status Code: 204 {} - Expected Fail Response:: HTTP Status Code: 401 {'message': 'unauthorized'} """ load = ScopeSchema().load(request.json) connect(flask_session['token'], load["project_id"]) flask_session["project_id"] = load["project_id"] return {}, 204
def delete(instance_id): """ **Delete specific instance** This function allows users to delete their instance specified by its ID. :param instance_id: id of the cloud instance :type instance_id: openstack instance id :return: empty json and http status code - Example:: curl -X DELETE bio-portal.metacentrum.cz/api/instances/instance_id/ -H 'Cookie: cookie from scope' -H 'content-type: application/json' - Expected Success Response:: HTTP Status Code: 204 {} - Expected Fail Response:: HTTP Status Code: 400 {} """ connection = connect(session['token'], session['project_id']) server = connection.compute.find_server(instance_id) if server is None: return {}, 400 connection.compute.delete_server(instance_id) return {}, 204
def post(): """ **Create new security group** This function allows users to create new security group. Its json input is specified by schema.SecurityGroupSchema :return: security group information in json and http status code - Example:: curl -X POST bio-portal.metacentrum.cz/api/security_groups/ -H 'Cookie: cookie from scope' -H 'content-type: application/json' --data json specified in schema - Expected Success Response:: HTTP Status Code: 201 json-format: see openstack.compute.v2.server - Expected Fail Response:: HTTP Status Code: 400 {"message": ...} """ connection = connect(session["token"], session["project_id"]) load = SecurityGroupSchema().load(request.json) new_security_group = connection.network.create_security_group( name=load["name"]) return new_security_group, 201
def get(instance_id): """ **Get instance metadata** This function allows users to get instance metadata. :param instance_id: id of the cloud instance :type instance_id: openstack instance id :return: instance information in json and http status code - Example:: curl -X GET bio-portal.metacentrum.cz/api/metadata/instance_id/ -H 'Cookie: cookie from scope' - Expected Success Response:: HTTP Status Code: 200 json-format: see openstack.compute.v2.server.Server - Expected Fail Response:: HTTP Status Code: 400 {"message": "instance not found"} """ connection = connect(session["token"], session["project_id"]) instance = connection.compute.find_server(instance_id) if instance is None: return {"message": "instance not found"}, 400 return connection.compute.get_server_metadata(instance).to_dict(), 200
def delete(floating_ip_id): floating_ip = floating_ip_id connection = connect(session["token"], session["project_id"]) for server in connection.compute.servers(): for values in server.addresses.values(): for address in values: if address["addr"] == floating_ip and address[ "OS-EXT-IPS:type"] == "floating": connection.compute.remove_floating_ip_from_server( server.id, floating_ip) return {}, 200 return {"message": "Address or server not found"}, 400
def delete(instance_id): """ **Get instance metadata** This function allows users to remove instance metadata. Its json input is specified by schema.DeleteMetadataSchema :param instance_id: id of the cloud instance :type instance_id: openstack instance :return: empty json and http status code - Example:: curl -X DELETE bio-portal.metacentrum.cz/api/metadata/instance_id/ -H 'Cookie: cookie from scope' 'content-type: application/json' --data json specified in schema - Expected Success Response:: HTTP Status Code: 204 {} - Expected Fail Response:: HTTP Status Code: 400 {"message": "instance not found"} or HTTP Status Code: 400 {"message": "key not in metadata"} """ connection = connect(session["token"], session["project_id"]) instance = connection.compute.find_server(instance_id) load = DeleteMetadataSchema().load(request.json) if instance is None: return {"message": "instance not found"}, 400 metadata = connection.compute.get_server_metadata( instance).to_dict()["metadata"] for key in load["keys"]: if metadata.get(key) is None: return {"message": "key not in metadata"}, 400 connection.compute.delete_server_metadata(instance, load["keys"]) return {}, 204
def get(instance_id=None): """ **Get specific instance** This function allows users to get their instance specified by its ID. If no parameter given, all users instances are returned :param instance_id: id of the cloud instance :type instance_id: openstack instance id or None :return: instance/s information in json and http status code - Example:: curl -X GET bio-portal.metacentrum.cz/api/instances/_your_instance_id/ -H 'Cookie: cookie from scope' -H 'content-type: application/json' - Expected Success Response:: HTTP Status Code: 200 json-format: see openstack.compute.v2.server or HTTP Status Code: 200 openstack.compute.v2.server array - Expected Fail Response:: HTTP Status Code: 404 {} """ connection = connect(session['token'], session['project_id']) if instance_id is not None: server = connection.compute.find_server(instance_id) if server is None: return {}, 404 return server, 200 else: tmp = connection.compute.servers() return [r for r in tmp], 200
def put(router_id): """ **Update gateway** This function allows users to add external gateway. Its json input is specified by schema.NetworkSchema :param instance_id: id of the cloud instance :type instance_id: openstack instance id or None :return: router information in json and http status code - Example:: curl -X PUT bio-portal.metacentrum.cz/api/gateways/ -H 'Cookie: cookie from scope' -H 'content-type: application/json' --data json specified in schema - Expected Success Response:: HTTP Status Code: 200 json-format: see openstack.network.v2.router - Expected Fail Response:: HTTP Status Code: 400 {"message": "Wrong router ID, router not found!"} """ connection = connect(session["token"], session["project_id"]) load = NetworkSchema().load(request.json) router = connection.network.find_router(router_id) if not router: return {"message": "Wrong router ID, router not found!"}, 400 router_gateway_request = { "router": { "external_gateway_info": { "network_id": load["external_network"] } } } return put("https://network.cloud.muni.cz/v2.0/routers/%s" % router_id, headers={ "X-Auth-Token": connection.authorize() }, json=router_gateway_request).json()
def post(): """ **Add new public key** This function allows users to add new public key. If keypair with given name doesnt exist, its created. In case keypair with same name exits and their keys are different, old key is deleted and new one is created. Otherwise returns keypair that already existed is returned Its json input is specified by :class:`~schema.CreateKeypairSchema` :return: keypair information in json and http status code - Example:: curl -X POST bio-portal.metacentrum.cz/api/keypairs/ -H 'Cookie: cookie from scope' -H 'content-type: application/json' --data json specified in schema - Expected Success Response:: HTTP Status Code: 200 json-format: see openstack.compute.v2.keypair.Keypair or HTTP Status Code: 201 json-format: see openstack.compute.v2.keypair.Keypair - Expected Fail Response:: HTTP Status Code: 400 {} """ connection = connect(session["token"], session["project_id"]) load = CreateKeypairSchema().load(request.json) key_pair = connection.compute.find_keypair(load["key_name"]) if not key_pair: return connection.compute.create_keypair(**load), 201 elif key_pair.public_key != load["public_key"]: connection.compute.delete_keypair(key_pair) return connection.compute.create_keypair(**load), 200 return key_pair, 200
def get(security_group_id=None): """ **Get/list security group/s** This function allows users to get their security group specified by its ID. If no parameter given, all users security groups are returned :param security_group_id: id of the security group :type security_group_id: openstack security group id or None :return: security group/s information in json and http status code - Example:: curl -X GET bio-portal.metacentrum.cz/api/security_group/_your_sgroup_id/ -H 'Cookie: cookie from scope' -H 'content-type: application/json' - Expected Success Response:: HTTP Status Code: 200 json-format: see openstack.network.v2.security_group or HTTP Status Code: 200 openstack.network.v2.security_group array - Expected Fail Response:: HTTP Status Code: 404 {} """ connection = connect(session["token"], session["project_id"]) if security_group_id is None: tmp = connection.network.security_groups() return [r for r in tmp], 200 else: security_group = connection.network.find_security_group( security_group_id) if security_group is None: return {}, 404 return security_group.to_dict(), 200
def get(keypair_id=None): """ **Get/list keypair** This function allows users to get their instance specified by its ID. If no parameter given, all users instances are returned :param keypair_id: id of the keypair :type keypair_id: openstack keypair id or None :return: keypair/s in json and http status code - Example:: curl -X GET bio-portal.metacentrum.cz/api/keypairs/_your_keypair_id/ -H 'Cookie: cookie from scope' -H 'content-type: application/json' - Expected Success Response:: HTTP Status Code: 200 json-format: see openstack.compute.v2.keypair.Keypair or HTTP Status Code: 200 openstack.compute.v2.keypair.Keypair array - Expected Fail Response:: HTTP Status Code: 404 {} """ connection = connect(session["token"], session["project_id"]) if keypair_id is None: tmp = connection.compute.keypairs() return [r for r in tmp], 200 else: key_pair = connection.compute.find_keypair(keypair_id) if key_pair is None: return {}, 404 return key_pair, 200
def get(network_id=None): """ **Get/list network** This function allows users to get their network specified by its ID. If no parameter given, all users networks are returned :param network_id: id of the network :type network_id: openstack network id or None :return: network/s in json and http status code - Example:: curl -X GET bio-portal.metacentrum.cz/api/networks/_your_keypair_id/ -H 'Cookie: cookie from scope' -H 'content-type: application/json' - Expected Success Response:: HTTP Status Code: 200 json-format: see openstack.network.v2.network.Network or HTTP Status Code: 200 openstack.network.v2..network.Network array - Expected Fail Response:: HTTP Status Code: 404 {} """ connection = connect(session["token"], session["project_id"]) if network_id is None: network = connection.network.networks() return [r for r in network], 200 network = connection.network.find_network(network_id) if network is None: return {}, 404 return network.to_dict(), 200
def get(floating_ip_id=None): """ **Get specific Floating IP** This function allows users to get their Floating IP specified by its ID. If no parameter given, all users FIPs are returned :param floating_ip_id: id of the floating ip :type floating_ip_id: openstack FIP id or None :return: FIP/s information in json and http status code - Example:: curl -X GET bio-portal.metacentrum.cz/api/floating_ips/_your_floating_ip/ -H 'Cookie: cookie from scope' -H 'content-type: application/json' - Expected Success Response:: HTTP Status Code: 200 json-format: see openstack.network.v2.floating_ip or HTTP Status Code: 200 openstack.network.v2.floating_ip array - Expected Fail Response:: HTTP Status Code: 404 {} """ connection = connect(session["token"], session["project_id"]) if floating_ip_id is None: ips = connection.network.ips() return [r for r in ips], 200 floating_ip = connection.network.get_ip(floating_ip_id) if floating_ip is None: return {}, 404 return floating_ip.to_dict(), 200
def get(router_id=None): """ **Get router** This function allows users to get their router specified by its ID (not implemented). If no parameter given, all users routers are returned :param router_id: id of the cloud router :type router_id: openstack router id or None :return: router/s information in json and http status code - Example:: curl -X GET http://bio-portal.metacentrum.cz/api/routers/ -H 'Cookie: cookie from scope' - Expected Success Response:: HTTP Status Code: 200 openstack.network.v2.router array - Expected Fail Response:: HTTP Status Code: 404 {} or HTTP Status Code: 501 {} """ if router_id is None: connection = connect(session["token"], session["project_id"]) routers = connection.network.routers() return [r for r in routers], 200 return {}, 501
def put(instance_id): """ **Update instance metadata** This function allows users to add/update instance metadata. Its json input is specified by schema.CreateMetadataSchema :param instance_id: id of the cloud instance :type instance_id: openstack instance id :return: instance information in json and http status code - Example:: curl -X PUT bio-portal.metacentrum.cz/api/metadata/instance_id/ -H 'Cookie: cookie from scope' -H 'content-type: application/json' --data json specified in schema - Expected Success Response:: HTTP Status Code: ?? json-format: see openstack.compute.v2.server.Server - Expected Fail Response:: HTTP Status Code: 400 {"message": "instance not found"} """ connection = connect(session["token"], session["project_id"]) instance = connection.compute.find_server(instance_id) metadata = CreateMetadataSchema().load(request.json)["metadata"] if instance is None: return {"message": "instance not found"}, 400 return connection.compute.set_server_metadata(instance, **metadata)
def post(): """ **Create new instance** This function allows users to start new instance. Its json input is specified by schema.StartServerSchema :return: instance information in json and http status code - Example:: curl -X POST bio-portal.metacentrum.cz/api/instances/ -H 'Cookie: cookie from scope' -H 'content-type: application/json' --data json specified in schema - Expected Success Response:: HTTP Status Code: 201 json-format: see openstack.compute.v2.server - Expected Fail Response:: HTTP Status Code: 400 {"message": "resoucre not found"} """ connection = connect(session['token'], session['project_id']) json = StartServerSchema().load(request.json) image = connection.compute.find_image(json["image"]) flavor = connection.compute.find_flavor(json["flavor"]) network = connection.network.find_network(json["network_id"]) key_pair = connection.compute.find_keypair(json["key_name"]) if (image is None) or (flavor is None) or (network is None) or (key_pair is None): return {"message": "resource not found"}, 400 if image.name == "debian-10-x86_64_bioconductor": req = requests.get( "https://raw.githubusercontent.com/bio-platform/bio-class-deb10/main/install/cloud-init-bioconductor-image.sh" ) text = encodeutils.safe_encode(req.text.encode("utf-8")) init_script = base64.b64encode(text).decode("utf-8") elif image.name == "debian-9-x86_64_bioconductor": req = requests.get( "https://raw.githubusercontent.com/bio-platform/bio-class/master/install/cloud-init-bioconductor-image.sh" ) text = encodeutils.safe_encode(req.text.encode("utf-8")) init_script = base64.b64encode(text).decode("utf-8") else: init_script = "" server = connection.compute.create_server(name=json["servername"], image_id=image.id, flavor_id=flavor.id, networks=[{ "uuid": network.id }], key_name=key_pair.name, metadata=json["metadata"], user_data=init_script) return server, 201
def post(): """ **Create new Floating IP** This function allows users to add new Floating IP to specified instance. If FIP doesnt exist, its created. If already exists and is not attached, then it will be attached to instance Its correct json input is specified by schema.FloatingIpSchema :return: floating information in json and http status code - Example:: curl -X GET bio-portal.metacentrum.cz/api/floating_ips/ -H 'Cookie: cookie from scope' -H 'content-type: application/json' --data: json specified in schema - Expected Success Response:: HTTP Status Code: 200 json-format: see openstack.network.v2.floating_ip or HTTP Status Code: 201 json-format: see openstack.network.v2.floating_ip - Expected Fail Response:: HTTP Status Code: 400 {"message": "Server not found"} or HTTP Status Code: 400 {"message": "Network not found"} """ connection = connect(session["token"], session["project_id"]) load = FloatingIpSchema().load(request.json) server = connection.compute.find_server(load["instance_id"]) if server is None: return {"message": "Server not found"}, 400 for values in server.addresses.values(): for address in values: if address["OS-EXT-IPS:type"] == "floating": return address, 200 for floating_ip in connection.network.ips(): if not floating_ip.fixed_ip_address: connection.compute.add_floating_ip_to_server( server, floating_ip.floating_ip_address) return floating_ip.to_dict(), 200 network = connection.network.find_network(load["network_id"]) if network is None: return {"message": "Network not found"}, 400 found_network_id = network.to_dict()["id"] floating_ip = connection.network.create_ip( floating_network_id=found_network_id) floating_ip = connection.network.get_ip(floating_ip) connection.compute.add_floating_ip_to_server( server, floating_ip.floating_ip_address) return floating_ip, 201
def post(security_group_id): """ **Add security group rule** This function allows users to add new security group rule. Its json input is specified by schema.SecurityGroupRuleSchema :param security_group_id: id of the security group id :type security_group_id: openstack security group id :return: information about created rule in json and http status code - Example:: curl -X POST bio-portal.metacentrum.cz/api/security_groups/security_group_id/security_group_rule/ -H 'Cookie: cookie from scope' -H 'content-type: application/json' --data json_specified_in_schema - Expected Success Response:: HTTP Status Code: 201 json-format: see openstack.network.v2.security_group_rule - Expected Fail Response:: HTTP Status Code: 409 {"message": ...} """ connection = connect(session["token"], session["project_id"]) load = SecurityGroupRuleSchema().load(request.json) if load["type"] == "ssh": new_rule = connection.network.create_security_group_rule( direction="ingress", protocol="tcp", port_range_max=22, port_range_min=22, security_group_id=security_group_id, ether_type="IPv4", ) if load["type"] == "all_icmp": new_rule = connection.network.create_security_group_rule( direction="ingress", protocol="ICMP", security_group_id=security_group_id, ether_type="IPv4", remote_ip_prefix="0.0.0.0/0") if load["type"] == "http": new_rule = connection.network.create_security_group_rule( direction="ingress", protocol="tcp", security_group_id=security_group_id, ether_type="IPv4", port_range_min="80", port_range_max="80", remote_ip_prefix="0.0.0.0/0") if load["type"] == "https": new_rule = connection.network.create_security_group_rule( direction="ingress", protocol="tcp", port_range_min="443", port_range_max="443", security_group_id=security_group_id, ether_type="IPv4", remote_ip_prefix="0.0.0.0/0") if load["type"] == "rdp": new_rule = connection.network.create_security_group_rule( direction="ingress", protocol="tcp", port_range_min="3389", port_range_max="3389", security_group_id=security_group_id, ether_type="IPv4", remote_ip_prefix="0.0.0.0/0") return new_rule.to_dict(), 201
def get(): """ **Get resource limits** This function allows users to get their resource limits and their usage. :return: limit information in json and http status code - Example:: curl -X GET bio-portal.metacentrum.cz/api/limits/ -H 'Cookie: cookie from scope' -H 'content-type: application/json' - Expected Success Response:: HTTP Status Code: 200 {"floating_ips": {"limit": 5, "used" : 2}, "instances": {"limit": 3, "used" : 1}, "cores": {"limit": 16, "used" : 6}, "ram": {"limit": 4, "used" : 1}, } - Expected Fail Response:: HTTP Status Code: 400 {} """ connection = connect(session["token"], session["project_id"]) limits = connection.compute.get_limits() absolute = limits["absolute"] quotas = get("https://network.cloud.muni.cz/v2.0/quotas/%s/" % session['project_id'], headers={ "Accept": "application/json", "User-Agent": "Mozilla/5.0 (X11;\ Ubuntu; Linux x86_64; rv:68.0)\ Gecko/20100101 Firefox/68.0", "X-Auth-Token": connection.authorize() }).json() ips = 0 for fip in connection.network.ips(): if fip.get("status") == "ACTIVE": ips += 1 res = { "floating_ips": { "limit": quotas["quota"]["floatingip"], "used": ips }, # get generator length "instances": { "limit": absolute["instances"], "used": absolute["instances_used"] }, "cores": { "limit": absolute["total_cores"], "used": absolute["total_cores_used"] }, "ram": { "limit": absolute["total_ram"], "used": absolute["total_ram_used"] } } return res, 200