Skip to content

Commit

Permalink
Update api version number requirements, and set version to 1
Browse files Browse the repository at this point in the history
  • Loading branch information
gschueler committed Feb 15, 2011
1 parent 51933e9 commit 52463ec
Show file tree
Hide file tree
Showing 10 changed files with 105 additions and 149 deletions.
48 changes: 22 additions & 26 deletions docs/en/09-api/01-chapter10.md
@@ -1,7 +1,7 @@
RunDeck API 1.2
RunDeck API
===========

RunDeck provides a Web API for use with your application. This describes the RunDeck API version 1.2.
RunDeck provides a Web API for use with your application. This describes the RunDeck API version `1`.

URLs
----
Expand All @@ -10,9 +10,9 @@ The RunDeck server has a "Base URL", where you access the server. Your RunDeck S

The root URL path for all calls to the API in this version is:

$RUNDECK_SERVER_URL/api
$RUNDECK_SERVER_URL/api/1

In this document we will leave off the `$RUNDECK_SERVER_URL` and simply display URLs as `/api/...`.
In this document we will leave off the `$RUNDECK_SERVER_URL/api/1` and simply display URLs as `/...`.

XML
----
Expand Down Expand Up @@ -44,14 +44,10 @@ The response should set a cookie named `JSESSIONID`.
API Version Number
------

The API Version Number is required to be included in all API calls.
The API Version Number is required to be included in all API calls within the URL.

You can include this number in two ways:
If the version number is not included or if the requested version number is unsupported, then the API call will fail.

* HTTP Request Header: `X-RUNDECK-API-VERSION: 1.2`
* Request Parameter: `api_version=1.2`

If the version number is not included the API call will fail.

Response Format
------
Expand Down Expand Up @@ -100,7 +96,7 @@ List the jobs that exist for a project.

URL:

/api/jobs
/jobs

Required parameters:

Expand All @@ -127,7 +123,7 @@ Run a job specified by ID.

URL:

/api/job/[ID]/run
/job/[ID]/run

Optional parameters:

Expand All @@ -142,7 +138,7 @@ Export the job definitions for in XML or YAML formats.

URL:

/api/jobs/export
/jobs/export

Required parameters:

Expand Down Expand Up @@ -172,7 +168,7 @@ Import job definitions in XML or YAML formats.

URL:

/api/jobs/import
/jobs/import

Method: `POST`

Expand Down Expand Up @@ -219,7 +215,7 @@ Export a single job definition in XML or YAML formats.

URL:

/api/job/[ID]
/job/[ID]

Optional parameters:

Expand All @@ -239,7 +235,7 @@ Delete a single job definition.

URL:

/api/job/[ID]
/job/[ID]

Method: `DELETE`

Expand All @@ -259,7 +255,7 @@ List the currently running executions for a project

URL:

/api/executions/running
/executions/running

Required Parameters:

Expand Down Expand Up @@ -307,7 +303,7 @@ Get the status for an execution by ID.

URL:

/api/execution/[ID]
/execution/[ID]

Result: an Item List of `executions` with a single item. See [Running Executions](#running-executions).

Expand All @@ -318,7 +314,7 @@ Abort a running execution by ID.

URL:

/api/execution/[ID]/abort
/execution/[ID]/abort

Result: The result will contain a `success/message` element will contain a descriptive message. The status of the abort action will be included as an element:

Expand All @@ -334,7 +330,7 @@ Run a command string.

URL:

/api/run/command
/run/command

Required Parameters:

Expand All @@ -354,7 +350,7 @@ Run a script.

URL:

/api/run/script
/run/script

Method: `POST`

Expand Down Expand Up @@ -382,7 +378,7 @@ List the existing projects on the server.

URL:

/api/projects
/projects

Result: An Item List of `projects`, each `project` of the form specified in the [Getting Project Info](#getting-project-info) section.

Expand All @@ -392,7 +388,7 @@ Get information about a project.

URL:

/api/project/NAME
/project/NAME

Result: An Item List of `projects` with one `project`. The `project` is of the form:

Expand All @@ -414,7 +410,7 @@ List the event history for a project.

URL:

/api/history
/history

Required Parameters:

Expand Down Expand Up @@ -476,7 +472,7 @@ List or query the resources for a project.

URL:

/api/resources
/resources

Required Parameters:

Expand Down Expand Up @@ -537,7 +533,7 @@ Get a specific resource within a project.

URL:

/api/resource/[name]
/resource/[name]

Required Parameters:

Expand Down
33 changes: 24 additions & 9 deletions rundeckapp/grails-app/conf/ApiRequestFilters.groovy
Expand Up @@ -24,27 +24,42 @@
*/

public class ApiRequestFilters {
def supported_versions=["1.2"]

public final static int API_CURRENT_VERSION=1
public final static int API_MIN_VERSION=API_CURRENT_VERSION
public final static int API_MAX_VERSION=API_CURRENT_VERSION

def allowed_actions=["renderError","invalid"]
def filters = {
/**
* Require api version request header or parameter
* Require valid api version in request path /api/version/...
*/
apiVersion(uri:'/api/**') {
before = {
if(controllerName=='api' && allowed_actions.contains(actionName)){
if(controllerName=='api' && allowed_actions.contains(actionName) || request.api_version){
return true
}
final def header = request.getHeader('X-RUNDECK-API-VERSION')
final def apiversion = params.api_version
def reqversion = header?:apiversion
if(!reqversion){

if(!params.api_version){
flash.errorCode='api.error.api-version.required'
redirect(controller:'api',action:'renderError')
return false
}else if (!supported_versions.contains(reqversion)) {
}
final def reqversion
def unsupported=!(params.api_version==~/^[1-9][0-9]*$/)
if(!unsupported){
try{
reqversion = Integer.parseInt(params.api_version)
if (reqversion < API_MIN_VERSION || reqversion > API_MAX_VERSION) {
unsupported = true
}
}catch (NumberFormatException e){
unsupported=true
}
}
if(unsupported){
flash.errorCode='api.error.api-version.unsupported'
flash.errorArgs=[reqversion]
flash.errorArgs=[params.api_version,API_CURRENT_VERSION]
redirect(controller:'api',action:'renderError')
return false
}
Expand Down
39 changes: 20 additions & 19 deletions rundeckapp/grails-app/conf/UrlMappings.groovy
Expand Up @@ -5,29 +5,30 @@ class UrlMappings {
// apply constraints here
}
}
//1.2 api url paths

"/api/$action?"(controller: 'api', action: 'invalid')
"/api/error"(controller: 'api', action: 'error')
"/api/execution/$id"(controller: 'execution', action: 'apiExecution')
"/api/execution/$id/abort"(controller: 'execution', action: 'apiExecutionAbort')
"/api/executions/running"(controller: 'menu', action: 'apiExecutionsRunning')
"/api/history"(controller: 'reports', action: 'apiHistory')
"/api/job/$id"(controller: 'api') {
/*******
* API url paths, v1
*/
"/api/$api_version/$action?"(controller: 'api', action: 'invalid')
"/api/$api_version/error"(controller: 'api', action: 'error')
"/api/$api_version/execution/$id"(controller: 'execution', action: 'apiExecution')
"/api/$api_version/execution/$id/abort"(controller: 'execution', action: 'apiExecutionAbort')
"/api/$api_version/executions/running"(controller: 'menu', action: 'apiExecutionsRunning')
"/api/$api_version/history"(controller: 'reports', action: 'apiHistory')
"/api/$api_version/job/$id"(controller: 'api') {
//passthrough from ApiController to ScheduledExecutionController
action = [GET: "apiJobExport", DELETE: "apiJobDelete"]
}
"/api/job/$id/run"(controller: 'scheduledExecution', action: 'apiJobRun')
"/api/jobs"(controller: 'menu', action: 'apiJobsList')
"/api/jobs/export"(controller: 'menu', action: 'apiJobsExport')
"/api/jobs/import"(controller: 'scheduledExecution', action: 'apiJobsImport')
"/api/project/$project?"(controller: 'framework', action: 'apiProject')
"/api/projects"(controller: 'framework', action: 'apiProjects')
"/api/$api_version/job/$id/run"(controller: 'scheduledExecution', action: 'apiJobRun')
"/api/$api_version/jobs"(controller: 'menu', action: 'apiJobsList')
"/api/$api_version/jobs/export"(controller: 'menu', action: 'apiJobsExport')
"/api/$api_version/jobs/import"(controller: 'scheduledExecution', action: 'apiJobsImport')
"/api/$api_version/project/$project?"(controller: 'framework', action: 'apiProject')
"/api/$api_version/projects"(controller: 'framework', action: 'apiProjects')
"/api/renderError"(controller: 'api', action: 'renderError')
"/api/resources"(controller: 'framework', action: 'apiResources')
"/api/resource/$name"(controller: 'framework', action: 'apiResource')
"/api/run/command"(controller: 'scheduledExecution', action: 'apiRunCommand')
"/api/run/script"(controller: 'scheduledExecution', action: 'apiRunScript')
"/api/$api_version/resources"(controller: 'framework', action: 'apiResources')
"/api/$api_version/resource/$name"(controller: 'framework', action: 'apiResource')
"/api/$api_version/run/command"(controller: 'scheduledExecution', action: 'apiRunCommand')
"/api/$api_version/run/script"(controller: 'scheduledExecution', action: 'apiRunScript')

//simplified url mappings for link generation
"/run/$id?"(controller: 'framework', action: 'nodes')
Expand Down
8 changes: 4 additions & 4 deletions rundeckapp/grails-app/controllers/ApiController.groovy
Expand Up @@ -6,7 +6,7 @@ class ApiController {

def invalid = {
response.setStatus(404)
request['error']="Invalid API Request: ${request.forwardURI}"
request['error']=g.message(code:'api.error.invalid.request',args:[request.forwardURI])
return error()
}
def renderError={
Expand All @@ -20,15 +20,15 @@ class ApiController {

public def success={ recall->
return render(contentType:"text/xml",encoding:"UTF-8"){
result(success:"true"){
result(success:"true", apiversion:ApiRequestFilters.API_CURRENT_VERSION){
recall(delegate)
}
}
}

def error={
return render(contentType:"text/xml",encoding:"UTF-8"){
result(error:"true"){
result(error:"true", apiversion:ApiRequestFilters.API_CURRENT_VERSION){
delegate.'error'{
if(flash.error){
message(flash.error)
Expand All @@ -47,7 +47,7 @@ class ApiController {
}
}
if(!flash.error && !flash.errors && !request.error && !request.errors){
message("Unknown error")
message(g.message(code:"api.error.unknown"))
}
}
}
Expand Down
3 changes: 2 additions & 1 deletion rundeckapp/grails-app/i18n/messages.properties
Expand Up @@ -247,9 +247,10 @@ execution.show.mode.Compact.desc=View all output collated by node

# API Messages
api.error.api-version.required=RunDeck API Version not specified
api.error.api-version.unsupported=RunDeck API Version is not supported: {0}
api.error.api-version.unsupported=RunDeck API Version is not supported: {0}, current version: {1}
api.error.user-unauthorized={0} is not authorized for: {1}
api.error.unknown=An unknown error occurred
api.error.invalid.request=Invalid API Request: {0}
api.error.parameter.required=parameter "{0}" is required
api.error.item.doesnotexist={0} does not exist: {1}
api.error.jobs.import.wrong-contenttype=The input was not the expected content type
Expand Down
18 changes: 4 additions & 14 deletions test/api/api-expect-error.sh
Expand Up @@ -3,34 +3,24 @@
# usage:
# api-expect-error.sh <URL> <params> <message>
# curls the URL with the params, and expects result error="true", with result message if specified
DIR=$(cd `dirname $0` && pwd)

errorMsg() {
echo "$*" 1>&2
}

DIR=$(cd `dirname $0` && pwd)

requrl="$1"
shift

# accept url argument on commandline, if '-' use default
VERSHEADER="X-RUNDECK-API-VERSION: 1.2"

# curl opts to use a cookie jar, and follow redirects, showing only errors
CURLOPTS="-s -S -L -c $DIR/cookies -b $DIR/cookies"
CURL="curl $CURLOPTS"

XMLSTARLET=xml


# now submit req
requrl="$1"
shift

params="$1"
shift


# get listing
$CURL -D $DIR/headers.out $CURL_REQ_OPTS --header "$VERSHEADER" ${requrl}?${params} > $DIR/curl.out
$CURL -D $DIR/headers.out $CURL_REQ_OPTS ${requrl}?${params} > $DIR/curl.out
if [ 0 != $? ] ; then
errorMsg "FAIL: failed query request"
exit 2
Expand Down
4 changes: 2 additions & 2 deletions test/api/include.sh
Expand Up @@ -24,7 +24,7 @@ xmlsel(){
$XMLSTARLET sel -T -t -v "$1" $2
}

VERSHEADER="X-RUNDECK-API-VERSION: 1.2"
API_VERSION="1"

# curl opts to use a cookie jar, and follow redirects, showing only errors
CURLOPTS="-s -S -L -c $DIR/cookies -b $DIR/cookies"
Expand All @@ -37,4 +37,4 @@ if [ "-" == "$1" ] ; then
fi
shift

APIURL="${RDURL}/api"
APIURL="${RDURL}/api/${API_VERSION}"

0 comments on commit 52463ec

Please sign in to comment.