Extending artifactory's pypi repos with plugins - artifactory

I am trying to migrate a legacy system to use artifactory. However I have two blockers:
the old scripts require PyPixmlrpc, which artifactory doesn't support
they also make use of upload_docs, not supported by artifactory's pypi implementation either
a smaller issue, the old scripts call register and they expect 200 instead of 204 http status code.
Would it be possible for me to write a plugin to implement this?
Looking at https://www.jfrog.com/confluence/display/RTF/User+Plugins I couldn't find a callback for when POST /api/pypi/<index-name> is requested.
If I can make
work for the methods we actually use, to just pretend it deployed docs and to respond with the correct status code I will be happy enough.

As you say, there is no plugin hook for the Pypi API endpoints. It would be possible to use the altResponse endpoint to customize artifact downloads, but then you would be restricted to GET requests with no request body, which is also not a good option for you.
I think the most viable approach would be to define a custom executions endpoint. With this, you can specify the acceptable method, read the body, and set your own response code and body. The main shortcoming with this is that you can't customize the path (it's always /api/plugins/execute/[execution_name]), but this can be worked around.
Execution endpoints can take params in the following form:
/api/plugins/execute/[execution_name]?params=[param_name]=[param_val]
Say your plugin takes a param path, which represents the API path your old scripts are going to call. Then you can set your base URL to /api/plugins/execute/[execution_name]?params=path=/, so that the API path is appended to the param. Alternatively, you can use nginx or another reverse proxy to rewrite the original API path to this form.
(Since you'll be using XML-RPC, I don't suppose you'll need to worry about any of this path stuff, but I'm including it anyway for completeness.)
Some issues with this approach:
Execution endpoints only allow String responses, so sending binary data in the response body might be finnicky. However, no such limitation exists with the request body.
If you need more than one request method, you'll need more than one execution endpoint. This means you'll need to use a reverse proxy to rewrite each method to a separate endpoint. Again, since XML-RPC just uses POST, this probably won't be an issue for you.
Execution endpoints can't customize response headers. Therefore, if your scripts expect a particular Content-Type or other header, you'll need to use a reverse proxy to insert it into the response.

Related

Apigee rest endpoint path mapping to custom path

I have rest end point /admn_resource_manager.I have created a apigee proxy to expose this.
I dont want to expose it like this to others as I want something like /adminmanager.
Is there any way to map /adminmanager to /admn_resource_manager using Apigee.
end user would use http://someurl.apigee/adminmanager instead of http://someurl.apigee/admn_resource_manager
I explored KeyValueMapoperation and AssignMessage in Apigee.
I am not sure if these are the right option to implement map path.I didn't get any example for this either.
The way you would think to do this would be to use the Assign Message policy and use the Set -> Path element. But this policy isn't currently working as designed for rewriting the proxy's target URL. See the Assign Message Guidance for more details.
To rewrite the incoming URL to a different target URL you can use the Assign Message Policy to set the entire URL (target.url) in the Target Endpoint flow, or you can use a JavaScript callout to set it. I chose to use a JavaScript callout because it gives a lot more control when rewriting the URL.
Here is an example project on Github I put together for this you can use to see how I did it. It uses the swapi.co api as the target endpoint. This proxy uses the Assign Message and JavaScript callout policies to rewrite the URL. Here's some details about it...
Proxy Endpoints
Create a proxy endpoint for each resource you are renaming.
This is where you setup the Assign Message policy to set the variables for the new path suffix.
Assign Message Policies
Set on the PreFlow of each proxy endpoint to set the targetPathSuffix and appendResourceIdToUrl (if needed) variables.
JavaScript Policy
Calls out to the URLRewrite.js file to execute the js code.
Set on the TargetEndpoints PreFlow and executes on each request
Uses the variables set in the Assign Message Policies to change the target.url variable.
I think Apigee can do it.
When I was started Apigee I have learned and try to understand from the picture below. (I think it is describe the main concept of this platform)
From your scenario,
You can specify the URL that you wants client to call maybe someurl.apigee/adminmanager or something else
Apigee is a middle also known as a Gateway. When you received the request from client, you can manage whatever you want. Of course, including pass your client to other URL like someurl.apigee/admn_resource_manager . (You just assigned new url to that request)
Because I'm not an expert as well so, you this link below can explain you more information.
Link:Using Flow Variables

How should I handle unsupported verbs on a resource?

I am developing a RESTful framework and am deciding how to handle an unsupported verb being called against a resource. For example, someone trying to PUT to a read-only resource.
My initial thought was a 404 error, but the error is not that the resource cannot be found, it exists, just the user is trying to use the resource incorrectly. Is there a more appropriate error code? What is the most common way in which this situation is handled?
Is it that you simply don't support a certain verb ie DELETE? In that case I'd use the following HTTP response code if someone uses a verb you don't support.
405 Method Not Allowed
A request was made of a resource using a request method not supported by that resource;[2] for example, using GET on a form which requires data to be presented via POST, or using PUT on a read-only resource. [source]
I don't think you would receive a request to your app at all if the incorrect verb were used (but that probably depends on which specific technologies you're using on the server side).
To be more helpful to potentially confused client connection attempts I suppose you could create a stub endpoint/action for each commonly incorrect verb, method combinations and then send back a friendly "use {verbname} instead for this request" text response, but I'd personally just invest a bit of time in better developer documentation : )
You could also seamlessly redirect to the correct action in those cases...

Is there any way to check if a POST url exists?

Is there any way to determine if a POST endpoint exists without actually sending a POST request?
For GET endpoints, it's not problem to check for 404s, but I'd like to check POST endpoints without triggering whatever action resides on the remote url.
Sending an OPTIONS request may work
It may not be implemented widely but the standard way to do this is via the OPTIONS verb.
WARNING: This should be idempotent but a non-compliant server may do very bad things
OPTIONS
Returns the HTTP methods that the server supports for specified URL. This can be used to check the functionality of a web server by requesting '*' instead of a specific resource.
More information here
This is not possible by definition.
The URL that you're posting to could be run by anything, and there is no requirement that the server behave consistently.
The best you could do is to send a GET and see what happens; however, this will result in both false positives and false negatives.
You could send a HEAD request, if the server you are calling support it - the response will typically be way smaller than a GET.
Does endpoint = script? It was a little confusing.
I would first point out, why would you be POSTing somewhere if it doesn't exist? It seems a little silly?
Anyway, if there is really some element of uncertainty with your POST URL, you can use cURL, then set the header option in the cURL response. I would suggest that if you do this that you save all validated POSTs if its likely that the POST url would be used again.
You can send your entire POST at the same time as doing the CURL then check to see if its errored out.
I think you probably answered this question yourself in your tags of your question with cURL.

Best method of post processing Nginx reverse proxy response

I'm doing some researching on switching from Apache to Nginx as a reverse proxy in front of a Grails application on the backend. I'm playing around with some URL rewriting and have run into an issue with the response being sent back from my back end. I can handle the location header rewrite but I'm wondering what the best way to process the actually content is for link and such.
Is nginx_substitutions_filter the preferred method or is there another module that folks use to do content replacement in the response body?
I've thought about creating a Grails plugin to handle rendering the correct content based on additional request headers but now I'm thinking that would be best handled outside the application to allow for the most flexibility and loose coupling.
Are there any articles about best practices for doing URL rewriting/response post processing for reverse proxy scenarios?
You can use the Lua module to capture the response and manipulate it like a Lua string. Silly example to upper case the output:
res = ngx.location.capture('/some/path')
ngx.print(string.upper(res.body))
see http://wiki.nginx.org/HttpLuaModule#ngx.location.capture
If you want to replace only the headers, HeadersMore 3rd party module is great for that.
Other than that, susbstiution module seems to be the only option.
But I would suggest you make the backend return the correct page. Modifying every response uses resources and takes time.

Better file uploading approach: HTTP post multipart or HTTP put?

Use-case: Upload a simple image file to a server, which clients could later retrieve
Designate a FTP Server for the job.
HTTP Put: It can directly upload files to a server without the need of a server side
component to handle the bytestream.
HTTP Post: Handle the bytestream by the server side component.
I think to safely use PUT on a public website requires even more effort than using POST (and is less commonly done) due to potential security issues. See http://bitworking.org/news/PUT_SaferOrDangerous.
OTOH, I think there are plenty of resources for safely uploading files with POST and checking them in the server side script, and that this is the more common practice.
PUT is only appropriate when you know the URL you are putting to.
You could also do:
4) POST to obtain a URL to which you then PUT the file.
edit: how are you going to get the HTTP server to decide whether it is OK to accept a particular PUT request?
What I usually do (via PHP) is HTTP POST.
And employ PHP's move_uploaded_file() to get it to whatever destination I want.

Resources