Documentation and Api Reference
* API Reference and documentation as two seperate sphinx document sets * Information from the Devstack guide and README moved over to the new documentation * Configuration examples * Examples of building plugins * Both use the new sphinx-rtd-theme Change-Id: If347905aa14b77b5943f1a9de97f6e287b98ce95
This commit is contained in:
parent
1e891daf21
commit
6cbf3fa7f7
@ -1,198 +0,0 @@
|
||||
# Deploying Adjutant in Devstack
|
||||
|
||||
This is a guide to setting up Adjutant in a running Devstack environment close to how we have been running it for development purposes.
|
||||
|
||||
This guide assumes you are running this in a clean ubuntu 16.04 virtual machine with sudo access.
|
||||
|
||||
## Deploy Devstack
|
||||
|
||||
Grab the Devstack repo.
|
||||
|
||||
```
|
||||
git clone https://github.com/openstack-dev/devstack.git
|
||||
```
|
||||
|
||||
And then define a basic localrc file with the password set and place that in the devstack folder (adjutant's default conf assumes 'openstack' as the admin password):
|
||||
```
|
||||
ADMIN_PASSWORD=openstack
|
||||
MYSQL_PASSWORD=openstack
|
||||
DATABASE_PASSWORD=openstack
|
||||
RABBIT_PASSWORD=openstack
|
||||
SERVICE_PASSWORD=openstack
|
||||
```
|
||||
|
||||
Run the devstack build:
|
||||
```
|
||||
./devstack/stack.sh
|
||||
```
|
||||
|
||||
Provided your VM has enough ram to handle a devstack install this should take a while, but go smoothly. Ideally give your VM 5gb or more of ram, any less can cause the devstack build to fail.
|
||||
|
||||
|
||||
## Deploy Adjutant
|
||||
|
||||
Grab the Adjutant repo.
|
||||
|
||||
```
|
||||
git clone https://github.com/catalyst/adjutant.git
|
||||
```
|
||||
|
||||
Then you'll want to setup a virtual environment.
|
||||
```
|
||||
cd adjutant
|
||||
virtualenv venv
|
||||
source venv/bin/activate
|
||||
```
|
||||
|
||||
Once that is done you can install Adjutant and its requirements:
|
||||
```
|
||||
pip install -r requirements.txt
|
||||
python setup.py develop
|
||||
```
|
||||
|
||||
If you prefer you can install it fully, but using develop instead allows you update the Adjutant code and have the service reflect that without rerunning the install.
|
||||
|
||||
|
||||
## Configure Adjutant
|
||||
|
||||
Most of the default conf values should work fine against devstack, but one thing that you will need to change is the uuid for the public network in DEFAULT_ACTION_SETTINGS for the actions NewDefaultNetworkAction and NewProjectDefaultNetworkAction. If you don't set this correctly, then signups or tasks using those actions will not be able to correctly create a default network as they cannot find the correct external public network.
|
||||
|
||||
On a fresh devstack there is only one public network so to find the public network uuid you can to run:
|
||||
```
|
||||
openstack network show public
|
||||
```
|
||||
And then grab the id value and put that into the Adjutant conf.
|
||||
|
||||
### Username is email
|
||||
|
||||
The example conf for Adjutant is setup with `USERNAME_IS_EMAIL = TRUE` which works on the assumption that usernames are emails. This is easy to change in the conf, but a fairly useful way of avoiding username clashes. If you set this to `False` then usernames will be required as well as emails for most tasks that deal with user creation.
|
||||
|
||||
Migrating between the two states hasn't yet been handled entirely, so once you pick a valuve for `USERNAME_IS_EMAIL` stick with it, or clear the database inbetween.
|
||||
|
||||
|
||||
## Running Adjutant
|
||||
|
||||
Still in the Adjutant repo directory, you will now need to run the migrations to build a basic database. By default this will use sqlite3, and for testing and development this is ideal and easier.
|
||||
```
|
||||
adjutant-api migrate
|
||||
```
|
||||
|
||||
Now the that the migrations have been setup and the database built run the service from the same directory, and it will revert to using the config file at 'conf/conf.yaml':
|
||||
```
|
||||
adjutant-api runserver 0.0.0.0:5050
|
||||
```
|
||||
Note: The port doesn't matter, but 5050 is a safe bet as it isn't used by any other DevStack services and we can then safely assume you will be using the same url for the rest of the guide.
|
||||
|
||||
Now you have Adjutant running, keep this window open as you'll want to keep an eye on the console output.
|
||||
|
||||
|
||||
## Add Adjutant to Keystone Catalogue
|
||||
|
||||
In a new SSH termimal connected to your ubuntu VM setup your credentials as environment variables:
|
||||
```
|
||||
export OS_USERNAME=admin
|
||||
export OS_PASSWORD=openstack
|
||||
export OS_PROJECT_NAME=demo
|
||||
export OS_USER_DOMAIN_NAME=default
|
||||
export OS_PROJECT_DOMAIN_NAME=default
|
||||
export OS_AUTH_URL=http://localhost/identity
|
||||
export OS_IDENTITY_API_VERSION=3
|
||||
export OS_REGION_NAME=RegionOne
|
||||
```
|
||||
|
||||
If you used the localrc file as given above, these should work.
|
||||
|
||||
Now setup a new service in Keystone for Adjutant and add an endpoint for it:
|
||||
```
|
||||
openstack service create registration --name adjutant
|
||||
openstack endpoint create adjutant public http://0.0.0.0:5050/v1 --region RegionOne
|
||||
```
|
||||
|
||||
|
||||
## Adjutant specific roles
|
||||
|
||||
To allow certain actions, Adjutant requires two special roles to exist. You can create them as such:
|
||||
```
|
||||
openstack role create project_admin
|
||||
openstack role create project_mod
|
||||
```
|
||||
Also because Adjutant by default also adds the role, you will want to create 'heat_stack_owner' which isn't by default present in devstack unless you install Heat:
|
||||
```
|
||||
openstack role create heat_stack_owner
|
||||
```
|
||||
|
||||
|
||||
## Testing Adjutant via the CLI
|
||||
|
||||
Now that the service is running, and the endpoint setup, you will want to install the client and try talking to the service:
|
||||
```
|
||||
sudo pip install python-adjutantclient
|
||||
```
|
||||
In this case the client should be safe to install globally with sudo, but you can also install it in the same virtualenv as Adjutant itself, or make a new virtualenv.
|
||||
|
||||
Now lets check the status of the service:
|
||||
```
|
||||
openstack adjutant status
|
||||
```
|
||||
|
||||
What you should get is:
|
||||
```
|
||||
{
|
||||
"error_notifications": [],
|
||||
"last_completed_task": null,
|
||||
"last_created_task": null
|
||||
}
|
||||
```
|
||||
Seeing as we've done nothing to the service yet this is the expected output.
|
||||
|
||||
To list the users on your current project (admin users are hidden by default):
|
||||
```
|
||||
openstack project user list
|
||||
```
|
||||
The above action is only possibly for users with the following roles: 'admin', 'project_admin', 'project_mod'
|
||||
|
||||
Now lets try inviting a new user:
|
||||
```
|
||||
openstack project user invite bob@example.com project_admin
|
||||
```
|
||||
You will then get a note saying your invitation has been sent. You can list your project users again with 'openstack project user list' to see your invite.
|
||||
|
||||
|
||||
Now if you look at the log in the Adjutant terminal you should still have open, you will see a print out of the email that would have been sent to bob@example.com. In the email is a line that looks like this:
|
||||
```
|
||||
http://192.168.122.160:8080/token/e86cbfb187d34222ace90845f900893c
|
||||
```
|
||||
Normally that would direct the user to a Horizon dashboard page where they can submit their password.
|
||||
|
||||
Since we don't have that running, your only option is to submit it via the CLI. This is cumbersome, but doable. From that url in your Adjutant output, grab the values after '.../token/'. That is bob's token. You can submit that via the CLI:
|
||||
```
|
||||
openstack admin task token submit <token> <json_data>
|
||||
openstack admin task token submit e86cbfb187d34222ace90845f900893c '{"password": "123456"}'
|
||||
```
|
||||
|
||||
Now if you get the user list, you will see bob is now active:
|
||||
```
|
||||
openstack project user list
|
||||
```
|
||||
|
||||
And also shows up as a user if you do:
|
||||
```
|
||||
openstack user list
|
||||
```
|
||||
|
||||
And since you are an admin, you can even take a look at the tasks themselves:
|
||||
```
|
||||
openstack admin task list
|
||||
```
|
||||
The topmost one should be your invite, and if you then do a show using that id you can see some details about it:
|
||||
```
|
||||
openstack admin task show <UUID>
|
||||
```
|
||||
|
||||
|
||||
## Setting Up Adjutant on Horizon
|
||||
|
||||
Adjutant has a Horizon UI plugin, the code and setup instructions for it can be found here:
|
||||
https://github.com/catalyst/adjutant-ui
|
||||
|
||||
If you do set this up, you will want to edit the default Adjutant conf to so that the TOKEN_SUBMISSION_URL is correctly set to point at your Horizon.
|
362
README.md
362
README.md
@ -6,364 +6,8 @@ Primarily built as user registration service that fits into the OpenStack ecosys
|
||||
|
||||
Useful for automating generic admin tasks that users might request but otherwise can't do without the admin role. Also allows automating the signup and creation of new users, but also allows such requests to require approval first if wanted. Due to issuing of uri+tokens for final steps of some actions, allows for a password submit/reset system as well.
|
||||
|
||||
### Functionality:
|
||||
## Documentation:
|
||||
|
||||
The main workflow consists of three possible steps which can be executed at different points in time, depending on how the TaskView is defined.
|
||||
Documentation is stored in doc/, a sphinx build of the documentation can be generated with the command 'tox -e docs'.
|
||||
|
||||
The base use case is three stages:
|
||||
|
||||
* Recieve Request
|
||||
* Validate request data against action serializers.
|
||||
* If valid, setup Task to represent the request, and the Actions specified for that TaskView.
|
||||
* The service runs the pre_approve function on all actions which should do any self validation to mark the actions themselves as valid or invalid, and populating the nodes in the Task based on that.
|
||||
* Admin Approval
|
||||
* An admin looks at the Task and its notes.
|
||||
* If they decide it is safe to approve, they do so.
|
||||
* If there are any invalid actions approval will do nothing until the action data is updated and initial validation is rerun.
|
||||
* The service runs the post_approve function on all actions.
|
||||
* If any of the actions require a Token to be issued and emailed for additional data such as a user password, then that will occur.
|
||||
* If no Token is required, the Task will run submit actions, and be marked as complete.
|
||||
* Token Submit
|
||||
* User submits the Token data.
|
||||
* The service runs the submit function on all actions, passing along the Token data, normally a password.
|
||||
* The action will then complete with the given final data.
|
||||
* Task is marked as complete.
|
||||
|
||||
There are cases and TaskViews that auto-approve, and thus automatically do the middle step right after the first. There are also others which do not need a Token and thus run the submit step as part of the second, or even all three at once. The exact number of 'steps' and the time between them depends on the definition of the TaskView.
|
||||
|
||||
Actions themselves can also effectively do anything within the scope of those three stages, and there is even the ability to chain multiple actions together, and pass data along to other actions.
|
||||
|
||||
The points that are modular, or will be made more modular in future, are the TaskViews and the actions tied to them. Adding new actions is easy, and attaching them to existing TaskViews is as well. Adding new TaskViews is also almost entirely modular.
|
||||
|
||||
Creation and management of Tasks, Tokens, and Notifications is not modular and is the framework around the defined Actions and TaskViews that handles how they are executed. This helps keep the way Actions are executed consistent and simpler to maintain, but does also allow Actions to run almost any logic within those consistent steps.
|
||||
|
||||
#### Version Endpoints:
|
||||
* ../ - GET
|
||||
* JSON containing details of the currently available versions (just v1 for now)
|
||||
|
||||
#### Admin Endpoints:
|
||||
|
||||
Endpoints for the management of tasks, tokens, and notifications. Most of these are limited by roles, or are for admin use only.
|
||||
|
||||
* ../v1/tasks - GET
|
||||
* A json containing all tasks.
|
||||
* Possible parameters are:
|
||||
* filters (specified below)
|
||||
* tasks_per_page, defaults to 25
|
||||
* page, page number to access (starts at 1)
|
||||
* ../v1/tasks/<uuid> - GET
|
||||
* Get details for a specific task.
|
||||
* ../v1/tasks/<uuid> - PUT
|
||||
* Update a task and retrigger pre_approve.
|
||||
* ../v1/tasks/<uuid> - POST
|
||||
* approve a task
|
||||
* ../v1/token - GET
|
||||
* A json containing all tokens.
|
||||
* Can also be filtered.
|
||||
* ../v1/token - POST
|
||||
* Reissue tokens for a given task.
|
||||
* ../v1/token - DELETE
|
||||
* Delete all expired tokens.
|
||||
* ../v1/token/<uuid> - GET
|
||||
* return a json describing the actions and required fields for the token.
|
||||
* ../v1/token/<uuid> - POST
|
||||
* submit the token.
|
||||
* ../v1/notification - GET
|
||||
* Get a list of all unacknowledged notifications.
|
||||
* Can also be filtered.
|
||||
* ../v1/notification - POST
|
||||
* Acknowledge a list of notifications.
|
||||
* ../v1/notification/<id> - GET
|
||||
* Details on a specific notification.
|
||||
* ../v1/notification/<id> - POST
|
||||
* Acknowledge a specific notification.
|
||||
|
||||
##### Filtering Tasks, Tokens, and Notifications
|
||||
|
||||
The task, token, and notification list endpoints can be filtered using a slight variant of the Django ORM filters.
|
||||
|
||||
This is done but sending a json with filters via HTTP parameters:
|
||||
```javascript
|
||||
{'filters': {'fieldname': { 'operation': 'value'}}
|
||||
```
|
||||
|
||||
Example:
|
||||
```javascript
|
||||
{'filters': {'task_id': { 'exact': '842433bb-fa08-4fc1-8c3b-aa9904ceb370'}}
|
||||
```
|
||||
|
||||
This looks a bit messy in the url as that json ends up being url-safe encoded, but doing the filters this way gives us a fairly large amount of flexibility.
|
||||
|
||||
Possible field lookup operations:
|
||||
https://docs.djangoproject.com/en/1.8/ref/models/querysets/#id4
|
||||
|
||||
|
||||
#### OpenStack Style TaskView Endpoints:
|
||||
|
||||
For ease of integration with OpenStack, these endpoints are setup to work and partly mimic the way similar ones would work in Keystone. They work and use the TaskViews, with some specical changes for certain required endpoints.
|
||||
|
||||
* ../v1/openstack/users - GET
|
||||
* Returns a list of users on your project, and their roles.
|
||||
* Also returns a list of pending user invites.
|
||||
* ../v1/openstack/users - POST
|
||||
* authenticated endpoint limited by role
|
||||
* auto-approved
|
||||
* add/invite a user to your project
|
||||
* adds an existing user with the selected role, or if non-existent user sends a uri+token to them for setup user before adding the role.
|
||||
* allows adding of users to own project without needing an admin role
|
||||
* ../v1/openstack/users/<user_id> - GET
|
||||
* Get details on the given user, including their roles on your project.
|
||||
* ../v1/openstack/users/<user_id> - DELETE
|
||||
* Used to cancel a pending user invite.
|
||||
* ../v1/openstack/users/<user_id>/roles - GET
|
||||
* Returns a list of roles for the user on your project.
|
||||
* ../v1/openstack/users/<user_id>/roles - PUT
|
||||
* Add roles to a user.
|
||||
* ../v1/openstack/users/<user_id>/roles - DELETE
|
||||
* Remove roles from a user.
|
||||
* ../v1/openstack/roles - GET
|
||||
* Returns a list of roles you are allowed to edit on your project.
|
||||
* ../v1/openstack/forgotpassword - POST
|
||||
* Submit a username/email to have a password reset token emailed to it.
|
||||
* ../v1/openstack/email-update - POST
|
||||
* Submit a new email address for your user.
|
||||
* Will notifiy old email address, and send a uri+token to new email to confirm.
|
||||
* On confirm will update email (or username if username is email)
|
||||
* ../v1/openstack/sign-up - POST
|
||||
* unauthenticated endpoint
|
||||
* for signup of new users/projects.
|
||||
* task requires manual approval, sends a uri+token for password setup after the project is created and setup.
|
||||
* create project
|
||||
* setup basic networking if needed
|
||||
* create user with random password
|
||||
* set user given password on token submit
|
||||
* ../v1/openstack/quotas/ - GET
|
||||
* JSON containg the specifications of each quota size, and data about the quota size for all regions in the current project
|
||||
* An additional parameter regions, containing a comma separated list of regions can be passed as well to limit the regions it will return data about.
|
||||
* ../v1/openstack/quotas/ - POST
|
||||
* Change the quota for all regions
|
||||
* The quota will automatically update if the new quota level is adjacent to the current one and there has not been an update to that region in the past 30 days
|
||||
* Other options will require admin approval before updating
|
||||
* POST body should be a JSON dict containing the size ('size') and optionally 'regions', a list of regions to update to
|
||||
|
||||
|
||||
#### (DEPRECATED) Default TaskView Endpoints:
|
||||
|
||||
Basic default endpoints for the TaskViews. These are still mostly used for testing, but are not really for production use. We will be getting rid of them eventually, although they do currently serve as a good basis for some of the more complex views.
|
||||
|
||||
* ../v1/actions/CreateProject - GET
|
||||
* return a json describing the actions and required fields for the endpoint.
|
||||
* ../v1/actions/CreateProject - POST
|
||||
* unauthenticated endpoint
|
||||
* for signup of new users/projects.
|
||||
* task requires manual approval, sends a uri+token for password setup after the project is created and setup.
|
||||
* create project
|
||||
* setup basic networking if needed
|
||||
* create user with random password
|
||||
* set user given password on token submit
|
||||
* ../v1/actions/InviteUser - GET
|
||||
* return a json describing the actions and required fields for the endpoint.
|
||||
* ../v1/actions/InviteUser - POST
|
||||
* authenticated endpoint limited by role
|
||||
* auto-approved
|
||||
* add/invite a user to your project
|
||||
* adds an existing user with the selected role, or if non-existent user sends a uri+token to them for setup user before adding the role.
|
||||
* allows adding of users to own project without needing an admin role
|
||||
* ../v1/actions/EditUser - GET
|
||||
* return a json describing the actions and required fields for the endpoint.
|
||||
* also returns a list of users that can be edited on your project.
|
||||
* ../v1/actions/EditUser - POST
|
||||
* authenticated endpoint limited by role
|
||||
* auto-approved
|
||||
* add/remove roles from a user on your project
|
||||
* ../v1/actions/ResetPassword - GET
|
||||
* return a json describing the actions and required fields for the endpoint.
|
||||
* ../v1/actions/ResetPassword - POST
|
||||
* unauthenticated endpoint
|
||||
* auto-approved
|
||||
* issue a uri+token to user email to reset password
|
||||
* ../v1/actions/UpdateEmail - GET
|
||||
* return a json describing the actions and required fields for the endpoint.
|
||||
* ../v1/actions/UpdateEmail - POST
|
||||
* Authenticated but open to any user
|
||||
* auto-approved
|
||||
* takes an email address
|
||||
* issue a uri+token to new email to update to that email
|
||||
|
||||
#### More API Documentation:
|
||||
|
||||
While in debug mode the service will supply online browsable documentation via Django REST Swagger.
|
||||
|
||||
This is viewable at:
|
||||
* ../docs
|
||||
|
||||
### Implementation Details:
|
||||
|
||||
#### Project Requirements:
|
||||
|
||||
The requirements for the service started as a system capable of taking requests for user sign up, waiting for approval, then on approval doing various setup and creation actions, followed by sending a uri+token to the user to set their password.
|
||||
|
||||
Creating a user directly in Keystone before approval also was to be avoided, and storing the password before approval was to be avoided.
|
||||
|
||||
Due to the steps involved, and the time between them, data had to be stored somewhere, and some representation of the request had to be stored as well. The ability to tie other actions and pieces of automation to the process also seemed useful and time saving considering the steps setting up a user might involve.
|
||||
|
||||
If that was the case, the system should ideally also have been modular enough to allow swapping of actions if circumstances changed, or new pieces of automation needed to be added or removed. Pushing as much logic to the concept of an 'action' seemed the ideal situation.
|
||||
|
||||
#### What is an Action?
|
||||
|
||||
Actions are a generic database model which knows what 'type' of action it is. On pulling the actions related to a Task from the database we wrap it into the appropriate class type which handles all the logic associated with that action type.
|
||||
|
||||
An Action is both a simple database representation of itself, and a more complex in memory class that handles all the logic around it.
|
||||
|
||||
Each action class has the functions "pre_approve", "post_approve", and "submit". These relate to stages of the approval process, and any python code can be executed in those functions, some of which should ideally be validation that the data passed makes sense.
|
||||
|
||||
Multiple actions can be chained together under one Task and will execute in the defined order. Actions can pass information along via an in memory cache/field on the task object, but that is only safe for the same stage of execution. Actions can also store data back to the database if their logic requires some info passed along to a later step of execution.
|
||||
|
||||
See **actions.models** and **actions.v1** for a good idea of Actions.
|
||||
|
||||
#### What is a Task?
|
||||
|
||||
A task is a top level model representation of the request. It wraps the request metadata, and based on the TaskView, will have actions associated with it.
|
||||
|
||||
See **api.models**.
|
||||
|
||||
#### What is a Token?
|
||||
|
||||
A token is a unique identifier linking to a task, so that anyone submitting the token will submit to the actions related to the task.
|
||||
|
||||
See **api.models**.
|
||||
|
||||
#### What is an TaskView
|
||||
|
||||
TaskViews are classes which extend the base TaskView class and use its imbuilt functions to process actions. They also have actions associated with them and the inbuilt functions from the base class are there to process and validate those against data coming in.
|
||||
|
||||
The TaskView will process incoming data and build it into a Task, and the related Action classes.
|
||||
|
||||
They are very simple to define as the inbuilt functions handle all the real logic, but defining which functions of those are called changes the view to create a task that either requires approval or auto-approves, with some cases auto-approval coming from the actions themselves if setup to do so.
|
||||
|
||||
The base TaskView class has three functions:
|
||||
|
||||
* get
|
||||
* just a basic view function that by default returns list of actions, and their required fields for the action view.
|
||||
* process_actions
|
||||
* needs to be called in the TaskView definition
|
||||
* A function to run the processing and validation of request data for actions.
|
||||
* Builds and returns the task object, or the validation errors.
|
||||
* approve
|
||||
* Takes a task and approves it, running post_approve actions and issuing a token if needed.
|
||||
* Used only if no admin approval is needed for Tasks create by this TaskView.
|
||||
|
||||
See **api.v1.tasks** and look at the TaskView class to get a better idea.
|
||||
|
||||
For a more complex variant, look at **api.v1.openstack** to see some more unique TaskViews specific to certain endpoints we needed to mimic OpenStack functionality.
|
||||
|
||||
In fact, at base these are ApiViews from Django Rest Framework, with some magic built in functions for task processing. You normally will want to pick a HTTP method for your core task itself, but having the other methods return data related to the task, or even trigger slight variants of a task is doable.
|
||||
|
||||
|
||||
## Development:
|
||||
|
||||
### Packaging and Installing:
|
||||
|
||||
While this is a Django application, it does not follow the standard Django folder structure because of certain packaging requirements. As such the project does not have a manage.py file and must be installed via setup.py or pip (if an sdist is built) to access the manage.py funcationality.
|
||||
|
||||
Rather than a standard Django application, treat this as a more standard python application in this regard.
|
||||
|
||||
Once installed, all the normal manage.py functions can be called directly on the 'adjutant-api' commandline function.
|
||||
|
||||
### Dev Environment:
|
||||
|
||||
Dev is mainly done within a virtualenv setup alongside a devstack deployment.
|
||||
|
||||
For more info, see:
|
||||
```
|
||||
DEVSTACK_GUIDE.md
|
||||
```
|
||||
|
||||
### Running tests:
|
||||
|
||||
We use tox to build a venv and run the tests. The same tests are also run for us in CI via jenkins.
|
||||
|
||||
Provided you have tox and its requirements installed running tests is very simple:
|
||||
|
||||
```
|
||||
$ tox
|
||||
```
|
||||
To run just action unit tests:
|
||||
```
|
||||
$ tox -- adjutant.actions
|
||||
```
|
||||
To run a single api test:
|
||||
```
|
||||
$ tox -- adjutant.api.v1.tests.test_api_taskview.TaskViewTests.test_duplicate_tasks_new_user
|
||||
```
|
||||
|
||||
### Adding Actions:
|
||||
|
||||
Adding new actions is done by creating a new django app in the actions module and defining the action models and their serializers. Action must extend the BaseAction class as defined in the **actions.models.v1.base** module. They also must register themselves to the global store of actions in **action.models**.
|
||||
|
||||
The documentation for this is mainly inline.
|
||||
|
||||
For examples of actions look in: **action.models.v1.users**, **action.models.v1.project**, and **action.models.v1.resources**
|
||||
|
||||
### Adding TaskViews:
|
||||
|
||||
TaskViews also need to be registered, and then are made active in the conf. To see how to register a TaskView look at **api.v1.models** and in the default conf under **ACTIVE_TASKVIEWS** too see how they are enabled.
|
||||
|
||||
For examples see **api.v1.openstack**.
|
||||
|
||||
|
||||
## Setup/Deployment:
|
||||
|
||||
### Custom Email Templates
|
||||
|
||||
Custom email templates are placed in:
|
||||
```
|
||||
/etc/adjutant/templates/
|
||||
```
|
||||
This is so that adding personalised or deployment specific templates is kept outside of the scope of the service itself and managed by the deployer.
|
||||
|
||||
## Plugins
|
||||
|
||||
As Adjutant is built on top of Django, we've used parts of Django's installed apps system to allow us a plugin mechanism that allows additional actions and views to be brought in via external sources. This allows company specific or deployer specific changes to easily live outside of the core service and simply extend the core service where and when need.
|
||||
|
||||
An example of such a plugin is here:
|
||||
https://github.com/catalyst/adjutant-odoo
|
||||
|
||||
## Future Plans:
|
||||
|
||||
Most future plans are around adding additional Actions to the service, but there will be some features that will require some refactoring.
|
||||
|
||||
While we are presently working with the Keystone V3 API, groups are not being used, but we intend to update the service to also manage and handle user groups. Managing Domains isn't really doable, but having the service be able to accept Domains, and multiple Domain back-ends is being planned.
|
||||
|
||||
Additional Actions and TaskViews we wish to add in the near future:
|
||||
|
||||
* Update Quota
|
||||
* Admin is required to do this
|
||||
* Allows users to request a quota increase and by requiring an admin to simply check, and confirm the request, will make the process faster.
|
||||
* Makes it effectively a quick 2 step process.
|
||||
* For eventual heirarchical-multi-tenancy this would ideally send these qouta increase requests to the parent for approval.
|
||||
* Hierarchical Multi-Tenancy in a single domain environment
|
||||
* 'project_admin' to be able to create sub-projects off the current scoped project.
|
||||
* This works as per normal in Keystone but does not require an admin role and enforces a naming convention to ensure unique namespaces per sub-projects and somewhat avoid the project name uniqueness issues per domain.
|
||||
* This also adds inherited role support to the already existing user invite and user role editing features.
|
||||
* some VERY basic sub-project quota (number of sub-projects allowed) via metadata stored on a project in Keystone, with quota calculations in Adjutant checking against number of sub-projects created in your WHOLE tree within given shifting window.
|
||||
* Stand-alone Setup Network Action + TaskView
|
||||
* For users who missed or forgot the step at Project creation, and want a quick network setup.
|
||||
* Blank Slate
|
||||
* Doesn't need admin, and could reuse your own token.
|
||||
* Clear my entire project of any and all resources.
|
||||
* Already doable via the APIs, but would be nice to have it in an easy to request action so clients don't need to code it themselves.
|
||||
* A way to setup and manage MFA credentials for a user
|
||||
* relies on work in Keystone around MFA, and serves only as a means to allow an initial challenge response that requires an initial passcode before MFA would become active for the user in Keystone.
|
||||
|
||||
Features that might require a slight refactor:
|
||||
|
||||
* Add optional serializers for token data.
|
||||
|
||||
Even less likely, and further far-future additions:
|
||||
|
||||
* Split the system into the api, a queue, and workers. That way tasks are processed asynchronously by the workers.
|
||||
* Will require a bunch of rethinking, but most of the core logic will be reused, with the workers simply waiting for events and executing them on the tasks/actions in much the same way as they are presently.
|
||||
* Remove concept of predefined action steps entirely, setup Actions to have any possible number of 'steps'.
|
||||
* Will require moving actions to an iterator style pattern with a "next_action" style function as the driving force.
|
||||
* Will alter how chaining actions together works, thus may require a lot of work to define a sensible pattern for chaining them together.
|
||||
An API Reference is stored in api-ref. This is also a sphinx build and can be generated with 'tox -e api-ref'.
|
||||
|
@ -16,10 +16,10 @@
|
||||
Django settings for Adjutant.
|
||||
|
||||
For more information on this file, see
|
||||
https://docs.djangoproject.com/en/1.8/topics/settings/
|
||||
https://docs.djangoproject.com/en/1.11/topics/settings/
|
||||
|
||||
For the full list of settings and their values, see
|
||||
https://docs.djangoproject.com/en/1.8/ref/settings/
|
||||
https://docs.djangoproject.com/en/1.11/ref/settings/
|
||||
"""
|
||||
|
||||
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
|
||||
|
BIN
api-ref/_static/fonts/glyphicons-halflings-regular.ttf
Normal file
BIN
api-ref/_static/fonts/glyphicons-halflings-regular.ttf
Normal file
Binary file not shown.
BIN
api-ref/_static/fonts/glyphicons-halflings-regular.woff
Normal file
BIN
api-ref/_static/fonts/glyphicons-halflings-regular.woff
Normal file
Binary file not shown.
0
api-ref/source/_static/fonts/.keep
Normal file
0
api-ref/source/_static/fonts/.keep
Normal file
478
api-ref/source/admin-api.inc
Normal file
478
api-ref/source/admin-api.inc
Normal file
@ -0,0 +1,478 @@
|
||||
*************************
|
||||
Administrative Endpoints
|
||||
*************************
|
||||
|
||||
Endpoints for the management of tasks, tokens, and notifications. Most of
|
||||
these are limited by roles, or are for admin use only.
|
||||
|
||||
Status
|
||||
=======
|
||||
.. rest_method:: GET /v1/status
|
||||
|
||||
Authentication: Administrator
|
||||
|
||||
Normal Response Code: 200
|
||||
|
||||
Simple status endpoint.
|
||||
|
||||
Returns a list of unacknowledged error notifications,
|
||||
and both the last created and last completed tasks.
|
||||
|
||||
|
||||
List Tasks
|
||||
===========
|
||||
.. rest_method:: GET /v1/tasks
|
||||
|
||||
Authentication: Administrator
|
||||
|
||||
Normal Response Codes: 200
|
||||
|
||||
Error Response Codes: 401, 403
|
||||
|
||||
Lists all tasks.
|
||||
|
||||
.. rest_parameters:: parameters.yaml
|
||||
|
||||
- filters: filters
|
||||
- page: page
|
||||
- tasks_per_page: tasks_per_page
|
||||
|
||||
Request Example
|
||||
-----------------
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
curl -H "X-Auth-Token: $OS_TOKEN" http://adjutant/v1/tasks
|
||||
|
||||
Response Example
|
||||
------------------
|
||||
.. code-block:: javascript
|
||||
|
||||
{
|
||||
"tasks": [
|
||||
{
|
||||
"action_notes": {
|
||||
"ResetUserPasswordAction": [
|
||||
"Existing user with matching email.",
|
||||
]
|
||||
},
|
||||
"actions": [
|
||||
{
|
||||
"action_name": "ResetUserPasswordAction",
|
||||
"data": {
|
||||
"domain_name": "Default",
|
||||
"email": "demo@example.com"
|
||||
},
|
||||
"valid": true
|
||||
}
|
||||
],
|
||||
"approved": true,
|
||||
"approved_by": {},
|
||||
"approved_on": "2017-08-30T21:29:48.484441Z",
|
||||
"cancelled": false,
|
||||
"completed": true,
|
||||
"completed_on": "2017-08-30T21:30:13.269498Z",
|
||||
"created_on": "2017-08-30T21:29:47.989851Z",
|
||||
"ip_address": "127.0.0.1",
|
||||
"keystone_user": {},
|
||||
"project_id": null,
|
||||
"task_type": "reset_password",
|
||||
"uuid": "d5c7901cfecd45ec9a87871035c9f662"
|
||||
},
|
||||
{
|
||||
"action_notes": {
|
||||
"NewProjectDefaultNetworkAction": [],
|
||||
"NewProjectWithUserAction": [],
|
||||
"SetProjectQuotaAction": []
|
||||
},
|
||||
"actions": [
|
||||
{
|
||||
"action_name": "NewProjectWithUserAction",
|
||||
"data": {
|
||||
"domain_id": "default",
|
||||
"email": "test@example.com",
|
||||
"parent_id": null,
|
||||
"project_name": "test_project"
|
||||
},
|
||||
"valid": true
|
||||
},
|
||||
{
|
||||
"action_name": "NewProjectDefaultNetworkAction",
|
||||
"data": {
|
||||
"region": "RegionOne",
|
||||
"setup_network": false
|
||||
},
|
||||
"valid": true
|
||||
},
|
||||
{
|
||||
"action_name": "SetProjectQuotaAction",
|
||||
"data": {},
|
||||
"valid": true
|
||||
}
|
||||
],
|
||||
"approved": false,
|
||||
"approved_by": {},
|
||||
"approved_on": None,
|
||||
"cancelled": false,
|
||||
"completed": false,
|
||||
"completed_on": null,
|
||||
"created_on": "2017-07-26T21:44:21.082248Z",
|
||||
"ip_address": "127.0.0.1",
|
||||
"keystone_user": {},
|
||||
"project_id": null,
|
||||
"task_type": "signup",
|
||||
"uuid": "370d952c63ba410c8704abc12cfd97b7"
|
||||
}
|
||||
}
|
||||
|
||||
Task Details
|
||||
=============
|
||||
.. rest_method:: GET /v1/tasks/<task_id>
|
||||
|
||||
Authentication: Administrator
|
||||
|
||||
Normal Response Codes: 200
|
||||
|
||||
Error Response Codes: 401, 403, 404
|
||||
|
||||
Gives details for the specific task.
|
||||
|
||||
.. rest_parameters:: parameters.yaml
|
||||
|
||||
- task_id: task_id
|
||||
|
||||
Request Example
|
||||
----------------
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
curl -H "X-Auth-Token: $OS_TOKEN" http://adjutant/v1/tasks/d5c7901cfecd45ec9a87871035c9f662
|
||||
|
||||
Response Example
|
||||
-----------------
|
||||
.. code-block:: javascript
|
||||
|
||||
{
|
||||
"action_notes": {
|
||||
"ResetUserPasswordAction": [
|
||||
"Existing user with matching email.",
|
||||
]
|
||||
},
|
||||
"actions": [
|
||||
{
|
||||
"action_name": "ResetUserPasswordAction",
|
||||
"data": {
|
||||
"domain_name": "Default",
|
||||
"email": "demo@example.com"
|
||||
},
|
||||
"valid": true
|
||||
}
|
||||
],
|
||||
"approved": true,
|
||||
"approved_by": {},
|
||||
"approved_on": "2017-08-30T21:29:48.484441Z",
|
||||
"cancelled": false,
|
||||
"completed": true,
|
||||
"completed_on": null,
|
||||
"created_on": "2017-08-30T21:29:47.989851Z",
|
||||
"ip_address": "127.0.0.1",
|
||||
"keystone_user": {},
|
||||
"project_id": null,
|
||||
"task_type": "reset_password",
|
||||
"uuid": "d5c7901cfecd45ec9a87871035c9f662"
|
||||
}
|
||||
|
||||
|
||||
Update Task
|
||||
============
|
||||
.. rest_method:: PUT /v1/tasks/<task_id>
|
||||
|
||||
Authentication: Project Admin or Project Moderator
|
||||
|
||||
Normal Response Codes: 200
|
||||
|
||||
Error Response Codes: 400, 401, 403, 404
|
||||
|
||||
Replace the data in an unapproved action and rerun the preapproval steps
|
||||
|
||||
|
||||
.. rest_parameters:: parameters.yaml
|
||||
|
||||
- task_data: task_data
|
||||
|
||||
Request Example
|
||||
----------------
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
curl -H "X-Auth-Token: $OS_TOKEN" \
|
||||
-H 'Content-Type: application/json' \
|
||||
-X PUT --data '{
|
||||
"project_name": "a_project",
|
||||
"email": "example.a@t.com",
|
||||
"region": "RegionOne",
|
||||
"setup_network": false
|
||||
}' http://0.0.0.0:5050/v1/tasks/19dbe418ecc14aeb94053f23eda01c78
|
||||
|
||||
Response Example
|
||||
----------------
|
||||
.. code-block:: javascript
|
||||
|
||||
{
|
||||
"notes": ["Task successfully updated."]
|
||||
}
|
||||
|
||||
Approve Task
|
||||
============
|
||||
.. rest_method:: POST /v1/tasks/<task_id>
|
||||
|
||||
Authentication: Administrator
|
||||
|
||||
Normal Response Codes: 200
|
||||
|
||||
Error Response Codes: 400, 401, 403, 404
|
||||
|
||||
Approves a task and runs the actions approval steps.
|
||||
|
||||
.. rest_parameters:: parameters.yaml
|
||||
|
||||
- task_id: task_id
|
||||
- approved: approved
|
||||
|
||||
Request Example
|
||||
----------------
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
curl -H "X-Auth-Token: $OS_TOKEN" -H 'Content-Type: application/json' \
|
||||
-d '{"approved": true}' http://0.0.0.0:5050/v1/tasks/19dbe418ecc14aeb94053f23eda01c78
|
||||
|
||||
Response Example
|
||||
-----------------
|
||||
.. code-block:: javascript
|
||||
|
||||
{
|
||||
"notes": ["Created Token."]
|
||||
}
|
||||
|
||||
In most cases an email will be sent after approval to the user who requested
|
||||
the task.
|
||||
|
||||
Cancel Task
|
||||
===========
|
||||
.. rest_method:: DELETE /v1/tasks/<task_id>
|
||||
|
||||
Authentication: Administrator, Project Admin or Project Moderator
|
||||
|
||||
Normal Response Codes: 200
|
||||
|
||||
Error Response Codes: 400, 401, 403, 404
|
||||
|
||||
Cancel a task. Tasks can be cancelled at any stage prior to their completion,
|
||||
an issued token for a cancelled task will be invalidated.
|
||||
|
||||
Project Admins and Project Moderators can only cancel tasks associated with
|
||||
their projects.
|
||||
|
||||
.. rest_parameters:: parameters.yaml
|
||||
|
||||
- task_id: task_id
|
||||
|
||||
List tokens
|
||||
============
|
||||
.. rest_method:: GET /v1/tokens
|
||||
|
||||
Authentication: Administrator
|
||||
|
||||
Normal Response Codes: 200
|
||||
|
||||
Error Response Codes: 401, 403
|
||||
|
||||
List all active tokens.
|
||||
|
||||
.. rest_parameters:: parameters.yaml
|
||||
|
||||
- filters: filters
|
||||
|
||||
Reissue Tokens
|
||||
===============
|
||||
.. rest_method:: POST /v1/tokens
|
||||
|
||||
Authentication: Administrator, Project Admin or Project Moderator
|
||||
|
||||
Normal Response Codes: 200
|
||||
|
||||
Error Response Codes: 400, 401, 403, 404
|
||||
|
||||
Reissue a token for the specified task.
|
||||
|
||||
.. rest_parameters:: parameters.yaml
|
||||
|
||||
- task_id: task_id_body
|
||||
|
||||
Delete Expired Tokens
|
||||
======================
|
||||
.. rest_method:: DELETE /v1/token
|
||||
|
||||
Authentication: Administrator
|
||||
|
||||
Normal Response Codes: 200
|
||||
|
||||
Error Response Codes: 401, 403
|
||||
|
||||
Delete all expired tokens.
|
||||
|
||||
Note that if a token has expired it will be deleted when someone attempts to
|
||||
access it, this will prevent the database from clogging up however will not
|
||||
have an effect on functionality.
|
||||
|
||||
|
||||
Get Token Details
|
||||
======================
|
||||
.. rest_method:: GET /v1/token/<token_id>
|
||||
|
||||
Authentication: Unauthenticated
|
||||
|
||||
Normal Response Codes: 200
|
||||
|
||||
Error Response Codes: 401, 403, 404
|
||||
|
||||
Details the actions, task_type and required fields of the token
|
||||
|
||||
.. rest_parameters:: parameters.yaml
|
||||
|
||||
- token_id: token_id
|
||||
|
||||
Request Example
|
||||
----------------
|
||||
.. code-block:: bash
|
||||
|
||||
curl http://0.0.0.0:5050/v1/tokens/771af33fb28e46aab45e265bd6a6d469
|
||||
|
||||
Response Example
|
||||
-----------------
|
||||
.. code-block:: javascript
|
||||
|
||||
{
|
||||
"actions": [
|
||||
"NewProjectWithUserAction",
|
||||
"NewProjectDefaultNetworkAction",
|
||||
"SetProjectQuotaAction"
|
||||
],
|
||||
"required_fields": [
|
||||
"password"
|
||||
],
|
||||
"task_type": "signup"
|
||||
}
|
||||
|
||||
|
||||
Submit Token
|
||||
======================
|
||||
.. rest_method:: POST /v1/token/<token_id>
|
||||
|
||||
Authentication: Unauthenticated
|
||||
|
||||
Normal Response Codes: 200
|
||||
|
||||
Error Response Codes: 400, 404
|
||||
|
||||
Submit a token and it's data to the last stage of an action execution.
|
||||
A 400 will be return if it does not contain all of the necessary fields.
|
||||
|
||||
.. rest_parameters:: parameters.yaml
|
||||
|
||||
- token_id: token_id
|
||||
- token_data: token_data
|
||||
|
||||
Request Example
|
||||
------------------
|
||||
.. code-block:: bash
|
||||
|
||||
curl -H 'Content-Type: application/json' \
|
||||
-d '{"password": "12345"}' http://0.0.0.0:5050/v1/tokens/771af33fb28e46aab45e265bd6a6d469
|
||||
|
||||
Response Example
|
||||
-----------------
|
||||
.. code-block:: javascript
|
||||
|
||||
{"notes":["Token submitted successfully."]}
|
||||
|
||||
In most cases an email will be sent after token submission, detailing what
|
||||
has changed.
|
||||
|
||||
List Notifications
|
||||
======================
|
||||
.. rest_method:: GET /v1/notification
|
||||
|
||||
Authentication: Administrator
|
||||
|
||||
Normal Response Codes: 200
|
||||
|
||||
Error Response Codes: 401, 403
|
||||
|
||||
List all unacknowledged notifications
|
||||
|
||||
.. rest_parameters:: parameters.yaml
|
||||
|
||||
- filters: filters
|
||||
|
||||
Acknowledge a List of Notifications
|
||||
===================================
|
||||
.. rest_method:: POST /v1/notification
|
||||
|
||||
Authentication: Administrator
|
||||
|
||||
Mark a given list of notifications as acknowledged
|
||||
|
||||
.. rest_parameters:: parameters.yaml
|
||||
|
||||
- notifications: notifications
|
||||
|
||||
Notification Details
|
||||
=====================
|
||||
.. rest_method:: GET /v1/notification/<notification_id>
|
||||
|
||||
Get details of a specific notification
|
||||
|
||||
.. rest_parameters:: parameters.yaml
|
||||
|
||||
- notification_id: notification_id
|
||||
|
||||
|
||||
Acknowledge Notification
|
||||
========================
|
||||
.. rest_method:: GET /v1/notification/<notification_id>
|
||||
|
||||
Acknowledge a specific notification.
|
||||
|
||||
.. rest_parameters:: parameters.yaml
|
||||
|
||||
- notification_id: notification_id
|
||||
- acknowledged: acknowledged
|
||||
|
||||
|
||||
|
||||
Filtering Tasks, Tokens, and Notifications
|
||||
==========================================
|
||||
The task, token, and notification list endpoints can be filtered using a
|
||||
slight variant of the Django ORM filters.
|
||||
|
||||
This is done but sending a json with filters via HTTP parameters:
|
||||
|
||||
.. code-block:: javascript
|
||||
|
||||
{'filters': {'fieldname': { 'operation': 'value'}}
|
||||
|
||||
|
||||
Example:
|
||||
|
||||
.. code-block:: javascript
|
||||
|
||||
{'filters': {'task_id': { 'exact': '842433bb-fa08-4fc1-8c3b-aa9904ceb370'}}
|
||||
|
||||
|
||||
This looks a bit messy in the url as that json ends up being url-safe encoded,
|
||||
but doing the filters this way gives us a fairly large amount of flexibility.
|
||||
|
||||
Possible field lookup operations:
|
||||
https://docs.djangoproject.com/en/1.11/ref/models/querysets/#id4
|
286
api-ref/source/conf.py
Normal file
286
api-ref/source/conf.py
Normal file
@ -0,0 +1,286 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Adjutant API Reference documentation build configuration file, created by
|
||||
# sphinx-quickstart on Wed Sep 6 13:55:48 2017.
|
||||
#
|
||||
# This file is execfile()d with the current directory set to its
|
||||
# containing dir.
|
||||
#
|
||||
# Note that not all possible configuration values are present in this
|
||||
# autogenerated file.
|
||||
#
|
||||
# All configuration values have a default; values that are commented out
|
||||
# serve to show the default.
|
||||
|
||||
# import sys
|
||||
# import os
|
||||
|
||||
|
||||
# If extensions (or modules to document with autodoc) are in another directory,
|
||||
# add these directories to sys.path here. If the directory is relative to the
|
||||
# documentation root, use os.path.abspath to make it absolute, like shown here.
|
||||
# sys.path.insert(0, os.path.abspath('.'))
|
||||
|
||||
# -- General configuration ------------------------------------------------
|
||||
|
||||
# If your documentation needs a minimal Sphinx version, state it here.
|
||||
# needs_sphinx = '1.0'
|
||||
|
||||
# Add any Sphinx extension module names here, as strings. They can be
|
||||
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
|
||||
# ones.
|
||||
extensions = [
|
||||
'sphinx.ext.intersphinx',
|
||||
'os_api_ref',
|
||||
'openstackdocstheme'
|
||||
]
|
||||
|
||||
html_theme = 'sphinx_rtd_theme'
|
||||
|
||||
# Theme options are theme-specific and customize the look and feel of a theme
|
||||
# further. For a list of options available for each theme, see the
|
||||
# documentation.
|
||||
# html_theme_options = {}
|
||||
|
||||
# Add any paths that contain custom themes here, relative to this directory.
|
||||
# html_theme_path = sphinx_bootstrap_theme.get_html_theme_path()
|
||||
|
||||
|
||||
repository_name = 'openstack/adjutant'
|
||||
bug_project = 'adjutant'
|
||||
bug_tag = ''
|
||||
|
||||
# Add any paths that contain templates here, relative to this directory.
|
||||
templates_path = ['_templates']
|
||||
|
||||
# The suffix of source filenames.
|
||||
source_suffix = '.rst'
|
||||
|
||||
# The encoding of source files.
|
||||
# source_encoding = 'utf-8-sig'
|
||||
|
||||
# The master toctree document.
|
||||
master_doc = 'index'
|
||||
|
||||
# General information about the project.
|
||||
project = u'Adjutant API Reference'
|
||||
copyright = u'2017, Catalyst IT Ltd'
|
||||
|
||||
# The version info for the project you're documenting, acts as replacement for
|
||||
# |version| and |release|, also used in various other places throughout the
|
||||
# built documents.
|
||||
#
|
||||
# The short X.Y version.
|
||||
version = '1'
|
||||
# The full version, including alpha/beta/rc tags.
|
||||
release = '1'
|
||||
|
||||
# The language for content autogenerated by Sphinx. Refer to documentation
|
||||
# for a list of supported languages.
|
||||
# language = None
|
||||
|
||||
# There are two options for replacing |today|: either, you set today to some
|
||||
# non-false value, then it is used:
|
||||
# today = ''
|
||||
# Else, today_fmt is used as the format for a strftime call.
|
||||
# today_fmt = '%B %d, %Y'
|
||||
|
||||
# List of patterns, relative to source directory, that match files and
|
||||
# directories to ignore when looking for source files.
|
||||
exclude_patterns = ['_build']
|
||||
|
||||
# The reST default role (used for this markup: `text`) to use for all
|
||||
# documents.
|
||||
# default_role = None
|
||||
|
||||
# If true, '()' will be appended to :func: etc. cross-reference text.
|
||||
# add_function_parentheses = True
|
||||
|
||||
# If true, the current module name will be prepended to all description
|
||||
# unit titles (such as .. function::).
|
||||
# add_module_names = True
|
||||
|
||||
# If true, sectionauthor and moduleauthor directives will be shown in the
|
||||
# output. They are ignored by default.
|
||||
# show_authors = False
|
||||
|
||||
# The name of the Pygments (syntax highlighting) style to use.
|
||||
pygments_style = 'sphinx'
|
||||
|
||||
# A list of ignored prefixes for module index sorting.
|
||||
# modindex_common_prefix = []
|
||||
|
||||
# If true, keep warnings as "system message" paragraphs in the built documents.
|
||||
# keep_warnings = False
|
||||
|
||||
|
||||
# -- Options for HTML output ----------------------------------------------
|
||||
|
||||
# The theme to use for HTML and HTML Help pages. See the documentation for
|
||||
# a list of builtin themes.
|
||||
# html_theme = 'openstackdocs'
|
||||
|
||||
# Theme options are theme-specific and customize the look and feel of a theme
|
||||
# further. For a list of options available for each theme, see the
|
||||
# documentation.
|
||||
# html_theme_options = {}
|
||||
|
||||
# Add any paths that contain custom themes here, relative to this directory.
|
||||
# html_theme_path = []
|
||||
|
||||
# The name for this set of Sphinx documents. If None, it defaults to
|
||||
# "<project> v<release> documentation".
|
||||
# html_title = None
|
||||
|
||||
# A shorter title for the navigation bar. Default is the same as html_title.
|
||||
# html_short_title = None
|
||||
|
||||
# The name of an image file (relative to this directory) to place at the top
|
||||
# of the sidebar.
|
||||
# html_logo = None
|
||||
|
||||
# The name of an image file (within the static path) to use as favicon of the
|
||||
# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
|
||||
# pixels large.
|
||||
# html_favicon = None
|
||||
|
||||
# Add any paths that contain custom static files (such as style sheets) here,
|
||||
# relative to this directory. They are copied after the builtin static files,
|
||||
# so a file named "default.css" will overwrite the builtin "default.css".
|
||||
html_static_path = ['_static']
|
||||
|
||||
# Add any extra paths that contain custom files (such as robots.txt or
|
||||
# .htaccess) here, relative to this directory. These files are copied
|
||||
# directly to the root of the documentation.
|
||||
# html_extra_path = []
|
||||
|
||||
# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
|
||||
# using the given strftime format.
|
||||
# html_last_updated_fmt = '%b %d, %Y'
|
||||
|
||||
# If true, SmartyPants will be used to convert quotes and dashes to
|
||||
# typographically correct entities.
|
||||
# html_use_smartypants = True
|
||||
|
||||
# Custom sidebar templates, maps document names to template names.
|
||||
# html_sidebars = {}
|
||||
|
||||
# Additional templates that should be rendered to pages, maps page names to
|
||||
# template names.
|
||||
# html_additional_pages = {}
|
||||
|
||||
# If false, no module index is generated.
|
||||
# html_domain_indices = True
|
||||
|
||||
# If false, no index is generated.
|
||||
# html_use_index = True
|
||||
|
||||
# If true, the index is split into individual pages for each letter.
|
||||
# html_split_index = False
|
||||
|
||||
# If true, links to the reST sources are added to the pages.
|
||||
# html_show_sourcelink = True
|
||||
|
||||
# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
|
||||
# html_show_sphinx = True
|
||||
|
||||
# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
|
||||
# html_show_copyright = True
|
||||
|
||||
# If true, an OpenSearch description file will be output, and all pages will
|
||||
# contain a <link> tag referring to it. The value of this option must be the
|
||||
# base URL from which the finished HTML is served.
|
||||
# html_use_opensearch = ''
|
||||
|
||||
# This is the file name suffix for HTML files (e.g. ".xhtml").
|
||||
# html_file_suffix = None
|
||||
|
||||
# Output file base name for HTML help builder.
|
||||
htmlhelp_basename = 'AdjutantAPIReferencedoc'
|
||||
|
||||
|
||||
# -- Options for LaTeX output ---------------------------------------------
|
||||
|
||||
# latex_elements = {
|
||||
# # The paper size ('letterpaper' or 'a4paper').
|
||||
# 'papersize': 'letterpaper',
|
||||
#
|
||||
# # The font size ('10pt', '11pt' or '12pt').
|
||||
# 'pointsize': '10pt',
|
||||
#
|
||||
# # Additional stuff for the LaTeX preamble.
|
||||
# 'preamble': '',
|
||||
# }
|
||||
|
||||
# Grouping the document tree into LaTeX files. List of tuples
|
||||
# (source start file, target name, title,
|
||||
# author, documentclass [howto, manual, or own class]).
|
||||
latex_documents = [
|
||||
('index', 'AdjutantAPIReference.tex',
|
||||
u'Adjutant API Reference Documentation',
|
||||
u'Catalyst IT Ltd', 'manual'),
|
||||
]
|
||||
|
||||
# The name of an image file (relative to this directory) to place at the top of
|
||||
# the title page.
|
||||
# latex_logo = None
|
||||
|
||||
# For "manual" documents, if this is true, then toplevel headings are parts,
|
||||
# not chapters.
|
||||
# latex_use_parts = False
|
||||
|
||||
# If true, show page references after internal links.
|
||||
# latex_show_pagerefs = False
|
||||
|
||||
# If true, show URL addresses after external links.
|
||||
# latex_show_urls = False
|
||||
|
||||
# Documents to append as an appendix to all manuals.
|
||||
# latex_appendices = []
|
||||
|
||||
# If false, no module index is generated.
|
||||
# latex_domain_indices = True
|
||||
|
||||
|
||||
# -- Options for manual page output ---------------------------------------
|
||||
|
||||
# One entry per manual page. List of tuples
|
||||
# (source start file, name, description, authors, manual section).
|
||||
man_pages = [
|
||||
('index', 'adjutantapireference', u'Adjutant API Reference Documentation',
|
||||
[u'Catalyst IT Ltd'], 1)
|
||||
]
|
||||
|
||||
# If true, show URL addresses after external links.
|
||||
# man_show_urls = False
|
||||
|
||||
|
||||
# -- Options for Texinfo output -------------------------------------------
|
||||
|
||||
# Grouping the document tree into Texinfo files. List of tuples
|
||||
# (source start file, target name, title, author,
|
||||
# dir menu entry, description, category)
|
||||
texinfo_documents = [
|
||||
('index', 'AdjutantAPIReference', u'Adjutant API Reference Documentation',
|
||||
u'Catalyst IT Ltd', 'AdjutantAPIReference',
|
||||
'A simple workflow framework to help automate admin and user tasks in '
|
||||
'and around OpenStack via a pluggable API exposing tasks made up of '
|
||||
'easily chainable actions.',
|
||||
'Miscellaneous'),
|
||||
]
|
||||
|
||||
# Documents to append as an appendix to all manuals.
|
||||
# texinfo_appendices = []
|
||||
|
||||
# If false, no module index is generated.
|
||||
# texinfo_domain_indices = True
|
||||
|
||||
# How to display URL addresses: 'footnote', 'no', or 'inline'.
|
||||
# texinfo_show_urls = 'footnote'
|
||||
|
||||
# If true, do not generate a @detailmenu in the "Top" node's menu.
|
||||
# texinfo_no_detailmenu = False
|
||||
|
||||
|
||||
# Example configuration for intersphinx: refer to the Python standard library.
|
||||
intersphinx_mapping = {'http://docs.python.org/': None}
|
38
api-ref/source/http-status.yaml
Normal file
38
api-ref/source/http-status.yaml
Normal file
@ -0,0 +1,38 @@
|
||||
200:
|
||||
default: |
|
||||
Request was successful.
|
||||
task-view: |
|
||||
Request successful, task submitted.
|
||||
202:
|
||||
default: |
|
||||
Request is accepted, but processing may take some time.
|
||||
400:
|
||||
default: |
|
||||
Bad request
|
||||
task-view: |
|
||||
Invalid task data, or missing parameters. The response body will include
|
||||
the details of the missing or invalid parameters.
|
||||
401:
|
||||
default: |
|
||||
User is unauthenticated, or X-Auth-Token has expired.
|
||||
403:
|
||||
default: |
|
||||
User has the wrong roles for this operation.
|
||||
404:
|
||||
default: |
|
||||
The requested resource could not be found.
|
||||
405:
|
||||
default: |
|
||||
Method is not valid for this endpoint and resource.
|
||||
409:
|
||||
default: |
|
||||
Conflict
|
||||
task-view: |
|
||||
Duplicate task.
|
||||
500:
|
||||
default: |
|
||||
Something went wrong with the service which prevents it from
|
||||
fulfilling the request.
|
||||
503:
|
||||
default: |
|
||||
Adjutant cannot connect to the Keystone Authentication Server.
|
15
api-ref/source/index.rst
Normal file
15
api-ref/source/index.rst
Normal file
@ -0,0 +1,15 @@
|
||||
.. Adjutant API Reference documentation master file, created by
|
||||
sphinx-quickstart on Wed Sep 6 13:55:48 2017.
|
||||
You can adapt this file completely to your liking, but it should at least
|
||||
contain the root `toctree` directive.
|
||||
|
||||
Welcome to Adjutant API Reference documentation!
|
||||
==================================================
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
v1-api-reference
|
||||
|
||||
Adjutant is a workflow framework built with Django and Django-Rest-Framework to
|
||||
automate basic admin tasks within an OpenStack Cloud.
|
152
api-ref/source/parameters.yaml
Normal file
152
api-ref/source/parameters.yaml
Normal file
@ -0,0 +1,152 @@
|
||||
# variables in header
|
||||
X-Auth-Token:
|
||||
description: |
|
||||
A valid authentication token for a user.
|
||||
in: header
|
||||
required: true
|
||||
type: string
|
||||
|
||||
# Path parameters
|
||||
notification_id:
|
||||
description: |
|
||||
The notification UUID, as given on list endpoints and in email correspondence.
|
||||
in: path
|
||||
required: true
|
||||
type: string
|
||||
task_id:
|
||||
description: |
|
||||
The task UUID as given in the task list and email correspondence.
|
||||
in: path
|
||||
required: true
|
||||
type: string
|
||||
token_id:
|
||||
description: |
|
||||
The token UUID, as given on the lists and in email correspondence.
|
||||
in: path
|
||||
required: true
|
||||
type: string
|
||||
user_id:
|
||||
description: |
|
||||
The user id, as seen on the ../v1/openstack/users page. Note that this
|
||||
is the openstack user id for confirmed users and the task ID for invited
|
||||
users.
|
||||
in: path
|
||||
required: true
|
||||
type: string
|
||||
|
||||
|
||||
# Query Parameters
|
||||
filters:
|
||||
description: |
|
||||
Django style filters for task, token and notification endpoints.
|
||||
See section `Filters` for details.
|
||||
in: query
|
||||
required: false
|
||||
type: dictionary
|
||||
region:
|
||||
description: |
|
||||
Region to setup the default network in.
|
||||
in: query
|
||||
required: true
|
||||
type: string
|
||||
setup_network:
|
||||
description: |
|
||||
Whether or not to setup a default network for a new project
|
||||
in: query
|
||||
required: true
|
||||
type: boolean
|
||||
page:
|
||||
description: |
|
||||
Page number to access, starts at and defaults to 1.
|
||||
in: query
|
||||
required: false
|
||||
type: int
|
||||
project_name:
|
||||
description: |
|
||||
Name for the new project.
|
||||
in: query
|
||||
required: true
|
||||
type: string
|
||||
tasks_per_page:
|
||||
description: |
|
||||
Limit on the tasks viewed on each page.
|
||||
in: query
|
||||
required: false
|
||||
type: int
|
||||
|
||||
|
||||
# Body Parameters
|
||||
acknowledged:
|
||||
description: |
|
||||
Confirmation for acknowledging a notification.
|
||||
in: body
|
||||
required: true
|
||||
type: boolean
|
||||
approved:
|
||||
description: |
|
||||
Confirmation to approve a task.
|
||||
in: body
|
||||
required: true
|
||||
type: boolean
|
||||
email:
|
||||
description: |
|
||||
New user email address.
|
||||
in: body
|
||||
required: true
|
||||
type: string
|
||||
email_password:
|
||||
description: |
|
||||
Email address for the user whose password needs resetting
|
||||
in: body
|
||||
required: true
|
||||
type: string
|
||||
email_signup:
|
||||
description: |
|
||||
Email address for the default user and project admin.
|
||||
in: body
|
||||
required: true
|
||||
type: string
|
||||
notifications:
|
||||
description: |
|
||||
List of notification UUIDs to acknowledge
|
||||
in: body
|
||||
required: true
|
||||
type: array
|
||||
roles:
|
||||
description: |
|
||||
List of roles for the user.
|
||||
in: body
|
||||
required: true
|
||||
type: array
|
||||
task_data:
|
||||
description: |
|
||||
A dictionary replacing all the data for a task. See the task details
|
||||
for what values should be included
|
||||
in: body
|
||||
required: true
|
||||
type: dictionary
|
||||
task_id_body:
|
||||
description: |
|
||||
The task UUID as given in the task list and email correspondence.
|
||||
in: body
|
||||
required: true
|
||||
type: int
|
||||
token_data:
|
||||
description: |
|
||||
A dictionary replacing all the data for a task. Use the token get request
|
||||
to see what should needs to be included.
|
||||
in: body
|
||||
required: true
|
||||
type: dictionary
|
||||
username:
|
||||
description: |
|
||||
New user username, required only if USERNAME_IS_EMAIL is false.
|
||||
in: body
|
||||
required: false
|
||||
type: string
|
||||
username_password:
|
||||
description: |
|
||||
Username, required only if USERNAME_IS_EMAIL is false.
|
||||
in: body
|
||||
required: false
|
||||
type: string
|
297
api-ref/source/taskviews.inc
Normal file
297
api-ref/source/taskviews.inc
Normal file
@ -0,0 +1,297 @@
|
||||
************************************
|
||||
OpenStack Style TaskView Endpoints
|
||||
************************************
|
||||
|
||||
A response of 'task created' means that the task requires admin approval and
|
||||
a response of 'created token' indicates that the task has been auto-approved
|
||||
and awaits the submission of an emailed token.
|
||||
|
||||
List users
|
||||
========================
|
||||
.. rest_method:: GET /v1/openstack/users
|
||||
|
||||
Authentication: Project Moderator or Admin
|
||||
|
||||
List current and pending users in the current project.
|
||||
|
||||
Request Example
|
||||
----------------
|
||||
.. code-block:: bash
|
||||
|
||||
curl -H "X-Auth-Token: $NOS_TOKEN" http://0.0.0.0:5050/v1/openstack/users
|
||||
|
||||
Response Example
|
||||
-----------------
|
||||
.. code-block:: javascript
|
||||
|
||||
{
|
||||
"users": [
|
||||
{
|
||||
"cohort": "Member",
|
||||
"email": "demo@example.com",
|
||||
"id": "",
|
||||
"manageable": false,
|
||||
"name": "demo",
|
||||
"roles": [
|
||||
"project_admin",
|
||||
"__member__"
|
||||
],
|
||||
"status": "Active"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
Invite User
|
||||
============
|
||||
.. rest_method:: POST /v1/openstack/users
|
||||
|
||||
Authentication: Project Moderator or Admin
|
||||
|
||||
An auto-approved task that will add a user to the project. If the user already
|
||||
exists it will add them directly, otherwise it will create a user when the
|
||||
invitee submits a token sent to them though email
|
||||
|
||||
.. rest_parameters:: parameters.yaml
|
||||
|
||||
- roles: roles
|
||||
- email: email
|
||||
- username: username
|
||||
|
||||
Request Example
|
||||
-----------------
|
||||
.. code-block:: bash
|
||||
|
||||
curl -H "X-Auth-Token: $NOS_TOKEN" http://0.0.0.0:5050/v1/openstack/users \
|
||||
-H 'Content-Type: application/json' \
|
||||
-d '{"roles": ["_member_"], "email": "new@example.com"}'
|
||||
|
||||
Response Example
|
||||
-----------------
|
||||
.. code-block:: javascript
|
||||
|
||||
{
|
||||
"notes": ["created token"]
|
||||
}
|
||||
|
||||
User Details
|
||||
=============
|
||||
.. rest_method:: GET /v1/openstack/users/<user_id>
|
||||
|
||||
Authentication: Project Moderator or Admin
|
||||
|
||||
Get details on the given user including their roles on your project
|
||||
|
||||
.. rest_parameters:: parameters.yaml
|
||||
|
||||
- user_id: user_id
|
||||
|
||||
Cancel User Invite
|
||||
==================
|
||||
.. rest_method:: DELETE /v1/openstack/users/<user_id>
|
||||
|
||||
Authentication: Project Moderator or Admin
|
||||
|
||||
Cancel a pending user invitation. Current users can be removed from your
|
||||
project by removing all of their roles.
|
||||
|
||||
.. rest_parameters:: parameters.yaml
|
||||
|
||||
- user_id: user_id
|
||||
|
||||
List User Roles
|
||||
==================
|
||||
.. rest_method:: GET /v1/openstack/users/<user_id>/roles
|
||||
|
||||
Authentication: Project Moderator or Admin
|
||||
|
||||
List all roles the user has on the current project
|
||||
|
||||
.. rest_parameters:: parameters.yaml
|
||||
|
||||
- user_id: user_id
|
||||
|
||||
Add User Roles
|
||||
==================
|
||||
.. rest_method:: PUT /v1/openstack/users/<user_id>/roles
|
||||
|
||||
Authentication: Project Moderator or Admin
|
||||
|
||||
Add the specified roles to the user on the current project.
|
||||
|
||||
There is additional authentication in the forms of what roles can be edited
|
||||
by the current user. If the target user has any role not editable by the
|
||||
current user the user will not be able to edit any of their roles.
|
||||
Editiable roles can be found at the ``List available roles`` endpoint.
|
||||
|
||||
|
||||
.. rest_parameters:: parameters.yaml
|
||||
|
||||
- user_id: user_id
|
||||
- roles: roles
|
||||
|
||||
Request Example
|
||||
-----------------
|
||||
.. code-block:: bash
|
||||
|
||||
curl -H "X-Auth-Token: $NOS_TOKEN" -H 'Content-Type: application/json' \
|
||||
-d '{"roles": ["project_mod"]}' -X PUT \
|
||||
http://0.0.0.0:5050/v1/openstack/users/5123ca764f3d40d79e3589e91f1ccb8f/roles
|
||||
|
||||
Response Example
|
||||
-----------------
|
||||
.. code-block:: javascript
|
||||
|
||||
{
|
||||
"notes": [
|
||||
"Task completed successfully."
|
||||
]
|
||||
}
|
||||
|
||||
Remove User Roles
|
||||
==================
|
||||
.. rest_method:: DELETE /v1/openstack/users/<user_id>/roles
|
||||
|
||||
Authentication: Project Moderator or Admin
|
||||
|
||||
Remove the specified roles from the user on the current project.
|
||||
|
||||
A project moderator will not be able to change the roles of a project admin.
|
||||
|
||||
.. rest_parameters:: parameters.yaml
|
||||
|
||||
- user_id: user_id
|
||||
- roles: roles
|
||||
|
||||
Request Example
|
||||
-----------------
|
||||
.. code-block:: bash
|
||||
|
||||
curl -H "X-Auth-Token: $NOS_TOKEN" -H 'Content-Type: application/json' \
|
||||
-d '{"roles": ["project_mod"]}' -X DELETE \
|
||||
http://0.0.0.0:5050/v1/openstack/users/5123ca764f3d40d79e3589e91f1ccb8f/roles
|
||||
|
||||
Response Example
|
||||
-----------------
|
||||
.. code-block:: javascript
|
||||
|
||||
{
|
||||
"notes": [
|
||||
"Task completed successfully."
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
List Available Roles
|
||||
=====================
|
||||
.. rest_method:: GET /v1/openstack/roles
|
||||
|
||||
Authentication: Project Moderator or Admin
|
||||
|
||||
List the roles available for the current user to modify.
|
||||
|
||||
Request Example
|
||||
----------------
|
||||
.. code-block:: bash
|
||||
|
||||
curl -H "X-Auth-Token: $NOS_TOKEN" http://0.0.0.0:5050/v1/openstack/roles/
|
||||
|
||||
Response Example
|
||||
-----------------
|
||||
.. code-block:: javascript
|
||||
|
||||
{
|
||||
"roles": [
|
||||
{
|
||||
"domain_id": null,
|
||||
"id": "b81efc1e23a043d0976dc39b3e2727c3",
|
||||
"links": {
|
||||
"self": "http://identity/v3/roles/b81efc1e23a043d0976dc39b3e2727c3"
|
||||
},
|
||||
"name": "project_mod"
|
||||
},
|
||||
{
|
||||
"domain_id": null,
|
||||
"id": "9fe2ff9ee4384b1894a90878d3e92bab",
|
||||
"links": {
|
||||
"self": "http://identity/v3/roles/9fe2ff9ee4384b1894a90878d3e92bab"
|
||||
},
|
||||
"name": "_member_"
|
||||
},
|
||||
]
|
||||
}
|
||||
|
||||
Password Reset
|
||||
===================
|
||||
.. rest_method:: POST /v1/openstack/users/password-reset
|
||||
|
||||
Authentication: Unauthenticated
|
||||
|
||||
Unauthenticated for forgotten password requests. If the email has an associated
|
||||
user a token will be sent to them to use to reset their password with.
|
||||
|
||||
.. rest_parameters:: parameters.yaml
|
||||
|
||||
- email: email_password
|
||||
- username: username_password
|
||||
|
||||
Request Example
|
||||
----------------
|
||||
.. code-block:: bash
|
||||
|
||||
curl -d '{"email": "demo@example.org"}' http://0.0.0.0:5050/v1/openstack/users/password-reset
|
||||
|
||||
Response Example
|
||||
-----------------
|
||||
.. code-block:: javascript
|
||||
|
||||
{
|
||||
"notes": ["If user with email exists, reset token will be issued."]
|
||||
}
|
||||
|
||||
Update Email Address
|
||||
=====================
|
||||
.. rest_method:: POST /v1/openstack/email-update
|
||||
|
||||
Authentication: Authenticated
|
||||
|
||||
Submit a new email address for the current user. A submission token will be
|
||||
sent to the new address, and a notification to the old email address. The
|
||||
account address will not change until the token submission.
|
||||
|
||||
.. rest_parameters:: parameters.yaml
|
||||
|
||||
- email: email
|
||||
|
||||
Sign Up
|
||||
========
|
||||
.. rest_method:: POST /v1/openstack/sign-up
|
||||
|
||||
Authentication: Unauthenticated
|
||||
|
||||
Account creation endpoint.
|
||||
|
||||
|
||||
.. rest_parameters:: parameters.yaml
|
||||
|
||||
- email: email
|
||||
- username: username
|
||||
- project_name: project_name
|
||||
- setup_network: setup_network
|
||||
- region: region
|
||||
|
||||
Request Example
|
||||
----------------
|
||||
.. code-block:: bash
|
||||
|
||||
curl -H 'X-Auth-Token: $OS_TOKEN' -H 'Content-Type: application/json' -d '{
|
||||
"email": "example@example.com", "project_name": "example_project"}'
|
||||
-X POST http://0.0.0.0:5050/v1/openstack/sign-up
|
||||
|
||||
Response Example
|
||||
-----------------
|
||||
.. code-block:: javascript
|
||||
|
||||
{
|
||||
"notes": ["task created"]
|
||||
}
|
93
api-ref/source/v1-api-reference.rst
Normal file
93
api-ref/source/v1-api-reference.rst
Normal file
@ -0,0 +1,93 @@
|
||||
#######################
|
||||
Version 1 API reference
|
||||
#######################
|
||||
|
||||
This is the reference for Adjutant when it is using the default configuration.
|
||||
Different deployments may exclude certain task views or include their own
|
||||
additional ones.
|
||||
|
||||
The core functionality of Adjutant is built around the concept of tasks and
|
||||
actions.
|
||||
|
||||
Actions are both concepts in the database and code that can execute whatever
|
||||
logic is necessary at each stage.
|
||||
|
||||
Tasks can bundle a number of actions and have 3 main steps.
|
||||
|
||||
1. A user submits a request to the specified endpoint.
|
||||
2. An admin approves the request, or it is automatically approved. At this
|
||||
point the admin can also update invalid data inside the task.
|
||||
3. If necessary a user will be emailed a token and will submit additional data
|
||||
(ie passwords or a confirmation) to finish the task.
|
||||
|
||||
Depending on the task and the data provided some steps may be skipped.
|
||||
|
||||
|
||||
******************
|
||||
Authentication
|
||||
******************
|
||||
|
||||
The 'X-Auth-Token' header value should be provided for authentication
|
||||
with a valid Keystone token.
|
||||
|
||||
******************
|
||||
HTTP Status Codes
|
||||
******************
|
||||
|
||||
.. rest_status_code:: success http-status.yaml
|
||||
|
||||
- 200
|
||||
- 200: task-view
|
||||
- 202
|
||||
|
||||
|
||||
.. rest_status_code:: error http-status.yaml
|
||||
|
||||
- 400
|
||||
- 401
|
||||
- 403
|
||||
- 404
|
||||
- 405
|
||||
- 409
|
||||
- 500
|
||||
- 503
|
||||
|
||||
|
||||
******************
|
||||
Service Discovery
|
||||
******************
|
||||
|
||||
Version Discovery Endpoint
|
||||
===========================
|
||||
.. rest_method:: GET /
|
||||
|
||||
Unauthenticated.
|
||||
|
||||
JSON containing details of the currently available versions (just v1 for now)
|
||||
|
||||
Normal response code: 200
|
||||
|
||||
Version One Details Endpoint
|
||||
=============================
|
||||
.. rest_method:: GET /v1
|
||||
|
||||
Unauthenticated.
|
||||
|
||||
Details V1 version details and the available taskviews and their fields.
|
||||
See below for further details on the individual taskviews.
|
||||
|
||||
Normal response code: 200
|
||||
|
||||
.. include:: admin-api.inc
|
||||
|
||||
.. include:: taskviews.inc
|
||||
|
||||
|
||||
************************************
|
||||
Additional API Documentation:
|
||||
************************************
|
||||
|
||||
While in debug mode the service will supply online browsable documentation via
|
||||
Django REST Swagger.
|
||||
|
||||
This is viewable at: ../docs
|
@ -53,7 +53,7 @@ KEYSTONE:
|
||||
password: openstack
|
||||
project_name: admin
|
||||
# MUST BE V3 API:
|
||||
auth_url: http://localhost:5000/v3
|
||||
auth_url: http://localhost/identity/v3
|
||||
domain_id: default
|
||||
|
||||
TOKEN_SUBMISSION_URL: http://192.168.122.160:8080/token/
|
||||
|
0
doc/source/_static/fonts/.keep
Normal file
0
doc/source/_static/fonts/.keep
Normal file
@ -30,7 +30,7 @@
|
||||
# Add any Sphinx extension module names here, as strings. They can be
|
||||
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
|
||||
# ones.
|
||||
extensions = []
|
||||
extensions = ['os_api_ref', ]
|
||||
|
||||
# Add any paths that contain templates here, relative to this directory.
|
||||
templates_path = ['_templates']
|
||||
@ -66,7 +66,10 @@ todo_include_todos = False
|
||||
# The theme to use for HTML and HTML Help pages. See the documentation for
|
||||
# a list of builtin themes.
|
||||
#
|
||||
# html_theme = 'alabaster'
|
||||
html_theme = 'sphinx_rtd_theme'
|
||||
|
||||
# Add any paths that contain custom themes here, relative to this directory.
|
||||
# html_theme_path = sphinx_bootstrap_theme.get_html_theme_path()
|
||||
|
||||
# Theme options are theme-specific and customize the look and feel of a theme
|
||||
# further. For a list of options available for each theme, see the
|
||||
|
247
doc/source/configuration.rst
Normal file
247
doc/source/configuration.rst
Normal file
@ -0,0 +1,247 @@
|
||||
Configuring Adjutant
|
||||
====================================
|
||||
|
||||
.. highlight:: yaml
|
||||
|
||||
Adjutant is designed to be highly configurable for various needs. The goal
|
||||
of Adjutant is to provide a variety of common tasks and actions that can
|
||||
be easily extended or changed based upon the needs of your OpenStack.
|
||||
|
||||
The default Adjutant configuration is found in conf/conf.yaml, and but will
|
||||
be overriden if a file is placed at ``/etc/adjutant/conf.yaml``.
|
||||
|
||||
The first part of the configuration file contains standard Django settings.
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
SECRET_KEY:
|
||||
|
||||
ALLOWED_HOSTS:
|
||||
- "*"
|
||||
|
||||
ADDITIONAL_APPS:
|
||||
- adjutant.api.v1
|
||||
- adjutant.actions.v1
|
||||
|
||||
DATABASES:
|
||||
default:
|
||||
ENGINE: django.db.backends.sqlite3
|
||||
NAME: db.sqlite3
|
||||
|
||||
LOGGING:
|
||||
|
||||
EMAIL_SETTINGS:
|
||||
EMAIL_BACKEND: django.core.mail.backends.console.EmailBackend
|
||||
|
||||
|
||||
If you have any plugins, ensure that they are also added to
|
||||
**ADDITIONAL_APPS**.
|
||||
|
||||
The next part of the confirguration file contains a number of settings for all
|
||||
taskviews.
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
USERNAME_IS_EMAIL: True
|
||||
|
||||
KEYSTONE:
|
||||
username:
|
||||
password:
|
||||
project_name:
|
||||
auth_url: http://localhost:5000/v3
|
||||
domain_id: default
|
||||
|
||||
TOKEN_SUBMISSION_URL: http://192.168.122.160:8080/token/
|
||||
|
||||
# time for the token to expire in hours
|
||||
TOKEN_EXPIRE_TIME: 24
|
||||
|
||||
ROLES_MAPPING:
|
||||
admin:
|
||||
- project_admin
|
||||
- project_mod
|
||||
- _member_
|
||||
project_admin:
|
||||
- project_admin
|
||||
- project_mod
|
||||
- _member_
|
||||
project_mod:
|
||||
- project_mod
|
||||
- heat_stack_owner
|
||||
- _member_
|
||||
|
||||
**USERNAME_IS_EMAIL** impacts account creation, and email modification actions.
|
||||
In the case that it is true, any task passing a username and email pair, the
|
||||
username will be ignored. This also impacts where emails are sent to.
|
||||
|
||||
The keystone settings must be for a user with administrative privileges,
|
||||
and must use the Keystone V3 API endpoint.
|
||||
|
||||
If you have Horizon configured with adjutant-api **TOKEN_SUBMISSION_URL**
|
||||
should point to that.
|
||||
|
||||
**ROLES_MAPPING** defines which roles can modify other roles. In the default
|
||||
configuration a user who has the role project_mod will not be able to
|
||||
modify any of the roles for a user with the project_admin role.
|
||||
|
||||
|
||||
Standard Task Settings
|
||||
----------------------
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
ACTIVE_TASKVIEWS:
|
||||
- UserRoles
|
||||
- UserDetail
|
||||
- UserResetPassword
|
||||
- UserSetPassword
|
||||
- UserList
|
||||
- RoleList
|
||||
- SignUp
|
||||
- UserUpdateEmail
|
||||
|
||||
All in use taskviews, including those that are from plugins must be included
|
||||
in this list. If a task is removed from this list its endpoint will not be
|
||||
accessable however users who have started tasks will still be able submit them.
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
DEFAULT_TASK_SETTINGS:
|
||||
duplicate_policy: null
|
||||
emails:
|
||||
initial:
|
||||
subject: Initial Confirmation
|
||||
reply: no-reply@example.com
|
||||
from: bounce+%(task_uuid)s@example.com
|
||||
template: initial.txt
|
||||
# html_template: initial.txt
|
||||
token:
|
||||
|
||||
completed:
|
||||
notifications:
|
||||
EmailNotification:
|
||||
standard:
|
||||
emails:
|
||||
- example@example.com
|
||||
reply: no-reply@example.com
|
||||
from: bounce+%(task_uuid)s@example.com
|
||||
template: notification.txt
|
||||
# html_template: completed.txt
|
||||
error:
|
||||
|
||||
The default settings can be overridden for individual tasks in the
|
||||
TASK_SETTINGS configuration, these are cascading overrides. Two additional
|
||||
options are available, overriding the default actions or adding in additional
|
||||
actions. These will run in the order specified.
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
signup:
|
||||
default_actions:
|
||||
- NewProjectAction
|
||||
invite_user:
|
||||
additional_actions:
|
||||
- SendAdditionalEmailAction
|
||||
|
||||
|
||||
By default duplicate tasks will be marked as invalid, however the duplicate
|
||||
policy can be set to 'cancel' to cancel duplicates and start a new class.
|
||||
|
||||
Email Settings
|
||||
~~~~~~~~~~~~~~
|
||||
The ``initial`` email will be sent after the user makes the request, the
|
||||
``token`` email will be sent after approval steps are run, and the
|
||||
``completed`` email will be sent after the token is submitted.
|
||||
|
||||
The emails will be sent to the current user, however this can be changed at
|
||||
the action level with the ``get_email()`` function.
|
||||
|
||||
Notification Settings
|
||||
~~~~~~~~~~~~~~~~~~~~~
|
||||
The type of notifications can be defined here for both standard notifications
|
||||
and error notifications::
|
||||
|
||||
notifications:
|
||||
EmailNotification:
|
||||
standard:
|
||||
emails:
|
||||
- example@example.com
|
||||
reply: no-reply@example.com
|
||||
template: notification.txt
|
||||
error:
|
||||
emails:
|
||||
- errors@example.com
|
||||
reply: no-reply@example.com
|
||||
template: notification.txt
|
||||
<other notification engine>:
|
||||
|
||||
Currently EmailNotification is the only available notification engine however
|
||||
new engines can be added through plugins and may have different settings.
|
||||
|
||||
|
||||
Action Settings
|
||||
---------------
|
||||
|
||||
Default action settings.
|
||||
Actions will each have their own specific settings, dependent on what they
|
||||
are for. The standard settings for a number of default actions are below:
|
||||
|
||||
An action can have it's settings overridden in the settings for it's task.
|
||||
This will only effect when the action is called through that specific task
|
||||
Overriding action settings for a specific task.
|
||||
|
||||
Email Templates
|
||||
---------------
|
||||
|
||||
Additional templates can be placed in ``/etc/adjutant/templates/`` and will be
|
||||
loaded in automatically. A plain text template and an HTML template can be
|
||||
specified separately. The context for this will include the task object and
|
||||
a dictionary containing the action objects.
|
||||
|
||||
Additional Emails
|
||||
------------------
|
||||
|
||||
The SendAdditionalEmailAction is designed to be added in at configuration
|
||||
for relevant tasks. It's templates are also passed a context dictionary with
|
||||
the task and actions available. By default the template is null and the email
|
||||
will not send.
|
||||
|
||||
The settings for this action should be defined within the action_settings
|
||||
for it's related task view.
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
additional_actions:
|
||||
- SendAdditionalEmailAction
|
||||
action_settings:
|
||||
SendAdditionalEmailAction:
|
||||
initial:
|
||||
subject: OpenStack Email Update Requested
|
||||
template: email_update_started.txt
|
||||
email_current_user: True
|
||||
|
||||
The additional email action can also send to a subset of people.
|
||||
|
||||
The user who made the request can be emailed with ::
|
||||
|
||||
email_current_user: true
|
||||
|
||||
Or the email can be sent to everyone who has a certain role on the project.
|
||||
(Multiple roles can also be specified)
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
email_roles:
|
||||
- project_admin
|
||||
|
||||
Or an email can be sent to a specified address in the task cache
|
||||
(key: ``additional_emails``) ::
|
||||
|
||||
email_in_task_cache: true
|
||||
|
||||
Or sent to an arbitrary administrative email address(es)::
|
||||
|
||||
email_additional_addresses:
|
||||
- admin@example.org
|
||||
|
||||
This can be useful in the case of large project affecting actions.
|
125
doc/source/design.rst
Normal file
125
doc/source/design.rst
Normal file
@ -0,0 +1,125 @@
|
||||
####################################
|
||||
Functionality
|
||||
####################################
|
||||
|
||||
Adjutant is built around tasks and actions.
|
||||
|
||||
Actions are a generic database model which knows what 'type' of action it is.
|
||||
On pulling the actions related to a Task from the database we wrap it into the
|
||||
appropriate class type which handles all the logic associated with that action
|
||||
type.
|
||||
|
||||
An Action is both a simple database representation of itself, and a more
|
||||
complex in memory class that handles all the logic around it.
|
||||
|
||||
Each action class has the functions "pre_approve", "post_approve", and
|
||||
"submit". These relate to stages of the approval process, and any python code
|
||||
can be executed in those functions, some of which should ideally be validation.
|
||||
|
||||
Multiple actions can be chained together under one Task and will execute in
|
||||
the defined order. Actions can pass information along via an in memory
|
||||
cache/field on the task object, but that is only safe for the same stage of
|
||||
execution. Actions can also store data back to the database if their logic
|
||||
requires some info passed along to a later step of execution.
|
||||
|
||||
See ``actions.models`` and ``actions.v1`` for a good idea of Actions.
|
||||
|
||||
Tasks originate at a TaskView, and start the action processing. They encompass
|
||||
the user side of interaction.
|
||||
|
||||
The main workflow consists of three possible steps which can be executed at
|
||||
different points in time, depending on how the TaskView and the actions within
|
||||
it are defined.
|
||||
|
||||
The base use case is three stages:
|
||||
|
||||
* Recieve Request
|
||||
* Validate request data against action serializers.
|
||||
* If valid, setup Task to represent the request, and the Actions specified
|
||||
for that TaskView.
|
||||
* The service runs the pre_approve function on all actions which should do
|
||||
any self validation to mark the actions themselves as valid or invalid,
|
||||
and populating the nodes in the Task based on that.
|
||||
* Admin Approval
|
||||
* An admin looks at the Task and its notes.
|
||||
* If they decide it is safe to approve, they do so.
|
||||
* If there are any invalid actions approval will do nothing until the
|
||||
action data is updated and initial validation is rerun.
|
||||
* The service runs the post_approve function on all actions.
|
||||
* If any of the actions require a Token to be issued and emailed for
|
||||
additional data such as a user password, then that will occur.
|
||||
* If no Token is required, the Task will run submit actions, and be
|
||||
marked as complete.
|
||||
* Token Submit
|
||||
* User submits the Token data.
|
||||
* The service runs the submit function on all actions, passing along the
|
||||
Token data, normally a password.
|
||||
* The action will then complete with the given final data.
|
||||
* Task is marked as complete.
|
||||
|
||||
There are cases and TaskViews that auto-approve, and thus automatically do the
|
||||
middle step right after the first. There are also others which do not need a
|
||||
Token and thus run the submit step as part of the second, or even all three at
|
||||
once. The exact number of 'steps' and the time between them depends on the
|
||||
definition of the TaskView.
|
||||
|
||||
Actions themselves can also effectively do anything within the scope of those
|
||||
three stages, and there is even the ability to chain multiple actions together,
|
||||
and pass data along to other actions.
|
||||
|
||||
Details for adding taskviews and actions can be found on the :doc:`plugins`
|
||||
page.
|
||||
|
||||
|
||||
What is an Action?
|
||||
====================
|
||||
|
||||
Actions are a generic database model which knows what 'type' of action it is.
|
||||
On pulling the actions related to a Task from the database we wrap it into the
|
||||
appropriate class type which handles all the logic associated with that action
|
||||
type.
|
||||
|
||||
An Action is both a simple database representation of itself, and a more
|
||||
complex in memory class that handles all the logic around it.
|
||||
|
||||
Each action class has the functions "pre_approve", "post_approve", and
|
||||
"submit". These relate to stages of the approval process, and any python code
|
||||
can be executed in those functions.
|
||||
|
||||
What is a Task?
|
||||
================
|
||||
A task is a top level model representation of the request. It wraps the
|
||||
request metadata, and based on the TaskView, will have actions associated with
|
||||
it.
|
||||
|
||||
|
||||
What is a Token?
|
||||
==================
|
||||
|
||||
A token is a unique identifier linking to a task, so that anyone submitting
|
||||
the token will submit to the actions related to the task.
|
||||
|
||||
What is an TaskView?
|
||||
====================
|
||||
|
||||
TaskViews are classes which extend the base TaskView class and use its inbuilt
|
||||
functions to process actions. They also have actions associated with them and
|
||||
the inbuilt functions from the base class are there to process and validate
|
||||
those against data coming in.
|
||||
|
||||
The TaskView will process incoming data and build it into a Task,
|
||||
and the related Action classes.
|
||||
|
||||
The base TaskView class has three functions:
|
||||
|
||||
* get
|
||||
* just a basic view function that by default returns list of actions,
|
||||
and their required fields for the action view.
|
||||
* process_actions
|
||||
* needs to be called in the TaskView definition
|
||||
* A function to run the processing and validation of request data for
|
||||
actions.
|
||||
* Builds and returns the task object, or the validation errors.
|
||||
|
||||
At their base TaskViews are django-rest ApiViews, with a few magic functions
|
||||
to wrap the task logic.
|
242
doc/source/devstack-guide.rst
Normal file
242
doc/source/devstack-guide.rst
Normal file
@ -0,0 +1,242 @@
|
||||
###############################
|
||||
Deploying Adjutant in Devstack
|
||||
###############################
|
||||
|
||||
This is a guide to setting up Adjutant in a running Devstack
|
||||
environment close to how we have been running it for development purposes.
|
||||
|
||||
This guide assumes you are running this in a clean ubuntu 16.04
|
||||
virtual machine with sudo access.
|
||||
|
||||
***************
|
||||
Deploy Devstack
|
||||
***************
|
||||
|
||||
Grab the Devstack repo::
|
||||
|
||||
git clone https://github.com/openstack-dev/devstack.git
|
||||
|
||||
|
||||
And then define a basic localrc file with the password set and place that in
|
||||
the devstack folder (adjutant's default conf assumes 'openstack' as the admin
|
||||
password)::
|
||||
|
||||
ADMIN_PASSWORD=openstack
|
||||
MYSQL_PASSWORD=openstack
|
||||
DATABASE_PASSWORD=openstack
|
||||
RABBIT_PASSWORD=openstack
|
||||
SERVICE_PASSWORD=openstack
|
||||
|
||||
Run the devstack build::
|
||||
|
||||
./devstack/stack.sh
|
||||
|
||||
Provided your VM has enough ram to handle a devstack install this should
|
||||
take a while, but go smoothly. Ideally give your VM 5gb or more of ram, any
|
||||
less can cause the devstack build to fail.
|
||||
|
||||
***************
|
||||
Deploy Adjutant
|
||||
***************
|
||||
|
||||
Grab the Adjutant repo::
|
||||
|
||||
git clone https://github.com/openstack/adjutant.git
|
||||
|
||||
Then you'll want to setup a virtual environment::
|
||||
|
||||
cd adjutant
|
||||
virtualenv venv
|
||||
source venv/bin/activate
|
||||
|
||||
Once that is done you can install Adjutant and its requirements::
|
||||
|
||||
pip install -r requirements.txt
|
||||
python setup.py develop
|
||||
|
||||
If you prefer you can install it fully, but using develop instead allows you
|
||||
update the Adjutant code and have the service reflect that without rerunning
|
||||
the install.
|
||||
|
||||
******************
|
||||
Configure Adjutant
|
||||
******************
|
||||
Most of the default conf values should work fine against devstack, but one
|
||||
thing that you will need to change is the uuid for the public network in
|
||||
`DEFAULT_ACTION_SETTINGS` for the actions NewDefaultNetworkAction and
|
||||
NewProjectDefaultNetworkAction. If you don't set this correctly, then signups
|
||||
or tasks using those actions will not be able to correctly create a default
|
||||
network as they cannot find the correct external public network.
|
||||
|
||||
On a fresh devstack there is only one public network so to find the public
|
||||
network uuid you can to run::
|
||||
|
||||
openstack network show public
|
||||
|
||||
And then grab the id value and put that into the Adjutant conf.
|
||||
|
||||
Username is email
|
||||
=================
|
||||
|
||||
The example conf for Adjutant is setup with `USERNAME_IS_EMAIL = TRUE` which
|
||||
works on the assumption that usernames are emails. This is easy to change in
|
||||
the conf, but a fairly useful way of avoiding username clashes. If you set this
|
||||
to `False` then usernames will be required as well as emails for most tasks
|
||||
that deal with user creation.
|
||||
|
||||
Migrating between the two states hasn't yet been handled entirely, so once you
|
||||
pick a value for `USERNAME_IS_EMAIL` stick with it, or clear the database
|
||||
inbetween.
|
||||
|
||||
******************
|
||||
Running Adjutant
|
||||
******************
|
||||
|
||||
Still in the Adjutant repo directory, you will now need to run the migrations
|
||||
to build a basic database. By default this will use sqlite3.::
|
||||
|
||||
adjutant-api migrate
|
||||
|
||||
Now the that the migrations have been setup and the database built run the
|
||||
service from the same directory, and it will revert to using the config file
|
||||
at 'conf/conf.yaml'::
|
||||
|
||||
adjutant-api runserver 0.0.0.0:5050
|
||||
|
||||
.. note::
|
||||
|
||||
The port doesn't matter, but 5050 is a safe bet as it isn't used by any
|
||||
other DevStack services and we can then safely assume you will be using
|
||||
the same url for the rest of the guide.
|
||||
|
||||
Now you have Adjutant running, keep this window open as you'll want to keep
|
||||
an eye on the console output.
|
||||
|
||||
**********************************
|
||||
Add Adjutant to Keystone Catalogue
|
||||
**********************************
|
||||
|
||||
In a new SSH termimal connected to your ubuntu VM setup your credentials as
|
||||
environment variables::
|
||||
|
||||
export OS_USERNAME=admin
|
||||
export OS_PASSWORD=openstack
|
||||
export OS_PROJECT_NAME=demo
|
||||
export OS_USER_DOMAIN_NAME=default
|
||||
export OS_PROJECT_DOMAIN_NAME=default
|
||||
export OS_AUTH_URL=http://localhost/identity
|
||||
export OS_IDENTITY_API_VERSION=3
|
||||
export OS_REGION_NAME=RegionOne
|
||||
|
||||
If you used the localrc file as given above, these should work.
|
||||
|
||||
Now setup a new service in Keystone for Adjutant and add an endpoint for it::
|
||||
|
||||
openstack service create registration --name adjutant
|
||||
openstack endpoint create adjutant public http://0.0.0.0:5050/v1 --region RegionOne
|
||||
|
||||
**********************************
|
||||
Adjutant specific roles
|
||||
**********************************
|
||||
|
||||
To allow certain actions, Adjutant requires two special roles to exist.
|
||||
You can create them as such::
|
||||
|
||||
openstack role create project_admin
|
||||
openstack role create project_mod
|
||||
|
||||
Also because Adjutant by default also adds the role, you will want to create
|
||||
'heat_stack_owner' which isn't by default present in devstack unless you
|
||||
install Heat::
|
||||
|
||||
openstack role create heat_stack_owner
|
||||
|
||||
|
||||
**********************************
|
||||
Testing Adjutant via the CLI
|
||||
**********************************
|
||||
|
||||
Now that the service is running, and the endpoint setup, you will want
|
||||
to install the client and try talking to the service::
|
||||
|
||||
sudo pip install python-adjutantclient
|
||||
|
||||
In this case the client should be safe to install globally with sudo, but you
|
||||
can also install it in the same virtualenv as Adjutant itself, or make a new
|
||||
virtualenv.
|
||||
|
||||
Now lets check the status of the service::
|
||||
|
||||
openstack adjutant status
|
||||
|
||||
|
||||
What you should get is::
|
||||
|
||||
{
|
||||
"error_notifications": [],
|
||||
"last_completed_task": null,
|
||||
"last_created_task": null
|
||||
}
|
||||
|
||||
Seeing as we've done nothing to the service yet this is the expected output.
|
||||
|
||||
To list the users on your current project (admin users are hidden by default)::
|
||||
|
||||
openstack project user list
|
||||
|
||||
The above action is only possibly for users with the following roles:
|
||||
'admin', 'project_admin', 'project_mod'
|
||||
|
||||
Now lets try inviting a new user::
|
||||
|
||||
openstack project user invite bob@example.com project_admin
|
||||
|
||||
You will then get a note saying your invitation has been sent. You can list
|
||||
your project users again with 'openstack project user list' to see your invite.
|
||||
|
||||
|
||||
Now if you look at the log in the Adjutant terminal you should still
|
||||
have open, you will see a print out of the email that would have been sent
|
||||
to bob@example.com. In the email is a line that looks like this::
|
||||
|
||||
http://192.168.122.160:8080/token/e86cbfb187d34222ace90845f900893c
|
||||
|
||||
Normally that would direct the user to a Horizon dashboard page where they can
|
||||
submit their password.
|
||||
|
||||
Since we don't have that running, your only option is to submit it via the CLI.
|
||||
This is cumbersome, but doable. From that url in your Adjutant output, grab the
|
||||
values after '.../token/'. That is bob's token. You can submit that via the
|
||||
CLI::
|
||||
|
||||
openstack admin task token submit <token> <json_data>
|
||||
openstack admin task token submit e86cbfb187d34222ace90845f900893c '{"password": "123456"}'
|
||||
|
||||
|
||||
Now if you get the user list, you will see bob is now active::
|
||||
|
||||
openstack project user list
|
||||
|
||||
And also shows up as a user if you do::
|
||||
|
||||
openstack user list
|
||||
|
||||
|
||||
And since you are an admin, you can even take a look at the tasks themselves::
|
||||
|
||||
openstack admin task list
|
||||
|
||||
The topmost one should be your invite, and if you then do a show using that
|
||||
id you can see some details about it::
|
||||
|
||||
openstack admin task show <UUID>
|
||||
|
||||
|
||||
**********************************
|
||||
Setting Up Adjutant on Horizon
|
||||
**********************************
|
||||
Adjutant has a Horizon UI plugin, the code and setup instructions for it can
|
||||
be found `here <https://github.com/openstack/adjutant-ui>`_
|
||||
|
||||
If you do set this up, you will want to edit the default Adjutant conf to so
|
||||
that the TOKEN_SUBMISSION_URL is correctly set to point at your Horizon.
|
@ -3,17 +3,87 @@
|
||||
You can adapt this file completely to your liking, but it should at least
|
||||
contain the root `toctree` directive.
|
||||
|
||||
####################################
|
||||
Welcome to Adjutant's documentation!
|
||||
====================================
|
||||
####################################
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
:caption: Contents:
|
||||
:maxdepth: 1
|
||||
|
||||
design
|
||||
devstack-guide
|
||||
configuration
|
||||
plugins
|
||||
|
||||
.. standard task views and actions
|
||||
|
||||
|
||||
A basic workflow framework built using Django and Django-Rest-Framework to
|
||||
help automate Admin tasks within an OpenStack cluster.
|
||||
|
||||
Indices and tables
|
||||
==================
|
||||
The goal of Adjutant is to provide a place and standard actions to fill in
|
||||
functionality missing from Keystone, and allow for the easy addition of
|
||||
business logic into more complex tasks, and connections with outside systems.
|
||||
|
||||
* :ref:`genindex`
|
||||
* :ref:`search`
|
||||
Tasks are built around three states of initial submission, admin approval and
|
||||
token submission. All of the states are not always used in every task, but this
|
||||
format allows the easy implementation of systems requiring approval and checks
|
||||
final user data entry.
|
||||
|
||||
While this is a Django application, it does not follow the standard Django
|
||||
folder structure because of certain packaging requirements. As such the project
|
||||
does not have a manage.py file and must be installed via setup.py or pip.
|
||||
|
||||
Once installed, all the normal manage.py functions can be called directly on
|
||||
the 'adjutant-api' commandline function.
|
||||
|
||||
The command ``tox -e venv {your commands}`` can be used and will setup a
|
||||
virtual environment with all the required dependencies for you.
|
||||
|
||||
For example, running the server on port 5050 can be done with::
|
||||
tox -e venv adjutant-api runserver 0.0.0.0:5050
|
||||
|
||||
|
||||
************************
|
||||
Client and UI Libraries
|
||||
************************
|
||||
|
||||
Both a commandline/python and a horizon plugin exist for adjutant:
|
||||
|
||||
* `python-adjutantclient <https://github.com/openstack/python-adjutantclient>`_
|
||||
* `adjutant-ui <https://github.com/openstack/adjutant-ui>`_
|
||||
|
||||
|
||||
************************
|
||||
Tests and Documentation
|
||||
************************
|
||||
|
||||
Tests and documentation are managed by tox, they can be run simply with the
|
||||
command ``tox``.
|
||||
|
||||
To run just action unit tests::
|
||||
|
||||
tox adjutant.actions
|
||||
|
||||
To run a single api test::
|
||||
|
||||
tox adjutant.api.v1.tests.test_api_taskview.TaskViewTests.test_duplicate_tasks_new_user
|
||||
|
||||
Tox will run the tests in Python 2.7, Python 3.5 and produce a coverage report.
|
||||
|
||||
Api reference can be generated with the command ``tox -e api-ref`` . This will
|
||||
be placed in the ``api-ref/build`` directory, these docs can be generated with
|
||||
the command ``tox -e docs``, these will be placed inside the ``doc/build``
|
||||
directory.
|
||||
|
||||
|
||||
************************
|
||||
Contributing
|
||||
************************
|
||||
|
||||
Bugs and blueprints for Adjutant, its ui and client are managed `here on
|
||||
launchpad. <https://launchpad.net/adjutant>`_
|
||||
|
||||
Changes should be submitted through the OpenStack gerrit, the guide for
|
||||
contributing to OpenStack projects is
|
||||
`here <https://docs.openstack.org/contributor-guide/>`_ .
|
||||
|
171
doc/source/plugins.rst
Normal file
171
doc/source/plugins.rst
Normal file
@ -0,0 +1,171 @@
|
||||
##############################
|
||||
Creating Plugins for Adjutant
|
||||
##############################
|
||||
|
||||
As Adjutant is built on top of Django, we've used parts of Django's installed
|
||||
apps system to allow us a plugin mechanism that allows additional actions and
|
||||
views to be brought in via external sources. This allows company specific or
|
||||
deployer specific changes to easily live outside of the core service and simply
|
||||
extend the core service where and when need.
|
||||
|
||||
An example of such a plugin is here:
|
||||
https://github.com/catalyst/adjutant-odoo
|
||||
|
||||
New TaskViews should inherit from adjutant.api.v1.tasks.TaskView
|
||||
can be registered as such::
|
||||
|
||||
from adjutant.api.v1.models import register_taskview_class,
|
||||
|
||||
from myplugin import tasks
|
||||
|
||||
register_taskview_class(r'^openstack/sign-up/?$', tasks.OpenStackSignUp)
|
||||
|
||||
Actions must be derived from adjutant.actions.v1.base.BaseAction and are
|
||||
registered alongside their serializer::
|
||||
|
||||
from adjutant.actions.v1.models import register_action_class
|
||||
|
||||
register_action_class(NewClientSignUpAction, NewClientSignUpActionSerializer)
|
||||
|
||||
Serializers can inherit from either rest_framework.serializers.Serializer, or
|
||||
the current serializers in adjutant.actions.v1.serializers.
|
||||
|
||||
A task must both be registered with a valid URL and specified in
|
||||
ACTIVE_TASKVIEWS in the configuration to be accessible.
|
||||
|
||||
A new task from a plugin can effectively 'override' a default task by
|
||||
registering with the same URL, and sharing the task type. However it must have
|
||||
a different class name and the previous task must be removed from
|
||||
ACTIVE_TASKVIEWS.
|
||||
|
||||
|
||||
**********************
|
||||
Building Taskviews
|
||||
**********************
|
||||
|
||||
Examples of taskviews can be found in adjutant.api.v1.openstack
|
||||
|
||||
Minimally they can look like this::
|
||||
|
||||
class NewCreateProject(TaskView):
|
||||
|
||||
task_type = "new_create_project"
|
||||
|
||||
default_actions = ["NewProjectWithUserAction", ]
|
||||
|
||||
def post(self, request, format=None):
|
||||
processed, status = self.process_actions(request)
|
||||
|
||||
errors = processed.get('errors', None)
|
||||
if errors:
|
||||
self.logger.info("(%s) - Validation errors with task." %
|
||||
timezone.now())
|
||||
return Response(errors, status=status)
|
||||
|
||||
return Response(response_dict, status=status)
|
||||
|
||||
Access can be restricted with the decorators mod_or_admin, project_admin and
|
||||
admin decorators found in adjutant.api.utils. The request handlers are fairly
|
||||
standard django view handlers and can execute any needed code. Additional
|
||||
information for the actions should be placed in request.data.
|
||||
|
||||
|
||||
*********************
|
||||
Building Actions
|
||||
*********************
|
||||
|
||||
Examples of actions can be found in adjutant.actions.v1.
|
||||
|
||||
Minimally actions should define their required fields and implement 3
|
||||
functions::
|
||||
|
||||
required = [
|
||||
'user_id',
|
||||
'value1',
|
||||
]
|
||||
|
||||
def _pre_approve(self):
|
||||
self.perform_action('initial')
|
||||
|
||||
def _post_approve(self):
|
||||
self.perform_action('token')
|
||||
self.action.task.cache['value'] = self.value1
|
||||
|
||||
def _submit(self, data):
|
||||
self.perform_action('completed')
|
||||
self.add_note("Submit action performed")
|
||||
|
||||
Information set in the action task cache is available in email templates under
|
||||
task.cache.value, and the action data is available in action.ActionName.value.
|
||||
|
||||
If a token email is needed to be sent the action should also implement::
|
||||
|
||||
def _get_email(self):
|
||||
return self.keystone_user.email
|
||||
|
||||
If an action does not require outside approval this function should be run at
|
||||
the pre-approval stage::
|
||||
|
||||
self.set_auto_approve(True)
|
||||
|
||||
If an action requires a token this should be set at the post approval stage::
|
||||
|
||||
self.action.need_token = True
|
||||
self.set_token_fields(["confirm"])
|
||||
|
||||
All actions must be paired with a serializer to do basic data structure
|
||||
checking, but should also check data validity during the action. Serializers
|
||||
are django-rest-framework serializers, but there are also two base serializers
|
||||
available in adjutant.actions.v1.serializers, BaseUserNameSerializer and
|
||||
BaseUserIdSerializer.
|
||||
|
||||
All fields required for an action must be placed through the serializer
|
||||
otherwise they will be inaccessible to the action.
|
||||
|
||||
Example::
|
||||
|
||||
from adjutant.actions.v1.serializers import BaseUserIdSerializer
|
||||
from rest_framework import serializers
|
||||
|
||||
class NewActionSerializer(BaseUserIdSerializer):
|
||||
value_1 = serializers.CharField()
|
||||
|
||||
******************************
|
||||
Building Notification Engines
|
||||
******************************
|
||||
|
||||
Notification Engines can also be added through a plugin::
|
||||
|
||||
from adjutant.notifcations.models import NotificationEngine
|
||||
from django.conf import settings
|
||||
|
||||
class NewNotificationEngine(NotificationEngine):
|
||||
|
||||
def _notify(self, task, notification):
|
||||
if self.conf.get('do_this_thing'):
|
||||
# do something with the task and notification
|
||||
|
||||
|
||||
settings.NOTIFICATION_ENGINES.update(
|
||||
{'NewNotificationEngine': NewNotificationEngine})
|
||||
|
||||
They should be then refered to in conf.yaml::
|
||||
|
||||
TASK_SETTINGS:
|
||||
signup:
|
||||
notifications:
|
||||
NewNotificationEngine:
|
||||
standard:
|
||||
do_this_thing: True
|
||||
error:
|
||||
do_this_thing: False
|
||||
|
||||
|
||||
*************************************************
|
||||
Using the Identity Manager, and Openstack Clients
|
||||
*************************************************
|
||||
|
||||
The Identity Manager is designed to replace access to the Keystone Client. It
|
||||
can be imported from ``adjutant.actions.user_store.IdentityManager`` .
|
||||
Functions for access to some of the other Openstack Clients are in
|
||||
``adjutant.actions.openstack_clients``.
|
@ -2,3 +2,7 @@ mock==1.2.0
|
||||
flake8>=3.0.4
|
||||
coverage>=4.4.1
|
||||
sphinx!=1.6.1,>=1.5.1
|
||||
os-api-ref>=1.0.0 # Apache-2.0
|
||||
sphinx-catalystcloud-theme>=0.0.1 # MIT
|
||||
sphinx-rtd-theme>=0.2.4
|
||||
doc8
|
||||
|
10
tox.ini
10
tox.ini
@ -27,7 +27,15 @@ commands =
|
||||
commands = {posargs}
|
||||
|
||||
[testenv:docs]
|
||||
commands = python setup.py build_sphinx
|
||||
commands =
|
||||
doc8 doc/source
|
||||
python setup.py build_sphinx
|
||||
|
||||
[testenv:api-ref]
|
||||
commands =
|
||||
doc8 api-ref/source
|
||||
python setup.py build_sphinx -s api-ref/source/ --build-dir api-ref/build/
|
||||
|
||||
|
||||
[flake8]
|
||||
ignore = D100,D101,D102,D103,D104,D105,D200,D203,D202,D204,D205,D208,D400,D401
|
||||
|
Loading…
Reference in New Issue
Block a user